#include "priv.h"
#include "theater.h"
#include "browbs.h"
#include "resource.h"
#include "legacy.h"
#include "uxtheme.h"        // needed for Margin.
#include "mluisupp.h"
#include "apithk.h"

#define SUPERCLASS CBandSite

TCHAR GetAccelerator(LPCTSTR psz, BOOL bUseDefault);

#define ABS(x) (((x) < 0) ? -(x) : (x))
#define CX_TEXTOFFSET   6
#define CY_TEXTOFFSET   4
#define CX_TBOFFSET     1
#define CY_TBPADDING    1
#define CY_ETCH         2
#define CY_FLUFF        7


// *** IInputObject methods ***
HRESULT CBrowserBandSite::HasFocusIO()
{
    HWND hwnd = GetFocus();
    if (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB))
        return S_OK;
    else
        return SUPERCLASS::HasFocusIO();
}

// *** IDeskBarClient methods ***
HRESULT CBrowserBandSite::SetModeDBC(DWORD dwMode)
{
    if ((dwMode ^ _dwMode) & DBIF_VIEWMODE_VERTICAL) {
        // switching horizontal/vertical; need to toggle toolbar
        // since we hide toolbar for horizontal bars
        if (_hwndTBRebar) {
            if (dwMode & DBIF_VIEWMODE_VERTICAL) {
                ShowWindow(_hwndTBRebar, SW_SHOW);
                _fToolbar = _pCmdTarget ? TRUE : FALSE;
            } else {
                ShowWindow(_hwndTBRebar, SW_HIDE);
                _fToolbar = FALSE;
            }
        }
    }

    return SUPERCLASS::SetModeDBC(dwMode);
}

HRESULT CBrowserBandSite::TranslateAcceleratorIO(LPMSG lpMsg)
{
    TraceMsg(TF_ACCESSIBILITY, "CBrowserBandSite::TranslateAcceleratorIO (hwnd=0x%08X) key=%d", _hwnd, lpMsg->wParam);

    HRESULT hr = S_FALSE;

    ASSERT((lpMsg->message >= WM_KEYFIRST) && (lpMsg->message <= WM_KEYLAST));

#if 0   //Disabled until a better key combination can be determined
    // check for Control-Shift arrow keys and resize if necessary
    if ((GetKeyState(VK_SHIFT) < 0)  && (GetKeyState(VK_CONTROL) < 0))
    {
        switch (lpMsg->wParam)
        {
            case VK_UP:
            case VK_DOWN:
            case VK_LEFT:
            case VK_RIGHT:
                IUnknown_Exec(_punkSite, &CGID_DeskBarClient, DBCID_RESIZE, (DWORD)lpMsg->wParam, NULL, NULL);
                return S_OK;
        }
    }
#endif

    if (!g_fRunningOnNT && (lpMsg->message == WM_SYSCHAR))
    {
        // See AnsiWparamToUnicode for why this character tweak is needed
        
        lpMsg->wParam = AnsiWparamToUnicode(lpMsg->wParam);
    }

    //  Give toolbar a crack
    if (hr != S_OK && _hwndTB && SendMessage(_hwndTB, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
        return S_OK;
    else if (hr != S_OK && SendMessage(_hwndOptionsTB, TB_TRANSLATEACCELERATOR, 0, (LPARAM)lpMsg))
        return S_OK;

    // to get a mapping, forward system characters to toolbar (if any) or xBar
    if (WM_SYSCHAR == lpMsg->message)
    {
        if (hr == S_OK)
        {
            return S_OK;
        }

        if ((NULL != _hwndTB) && (NULL != _pCmdTarget))
        {
            UINT idBtn;

            if (SendMessage(_hwndTB, TB_MAPACCELERATOR, lpMsg->wParam, (LPARAM)&idBtn))
            {
                TCHAR szButtonText[MAX_PATH];

                //  comctl says this one is the one, let's make sure we aren't getting
                //  one of the unwanted "use the first letter" accelerators that it
                //  will return.
    
                if ((SendMessage(_hwndTB, TB_GETBUTTONTEXT, idBtn, (LPARAM)szButtonText) > 0) &&
                    (GetAccelerator(szButtonText, FALSE) != (TCHAR)-1))
                {
                    //  (tnoonan) - it feels kinda cheesy to send mouse messages, but 
                    //  I don't know of a cleaner way which will accomplish what we
                    //  want (like deal with split buttons, mutually exclusive 
                    //  buttons, etc.).
        
                    RECT rc;

                    SendMessage(_hwndTB, TB_GETRECT, idBtn, (LPARAM)&rc);

                    SendMessage(_hwndTB, WM_LBUTTONDOWN, MK_LBUTTON, MAKELONG(rc.left, rc.top));
                    SendMessage(_hwndTB, WM_LBUTTONUP, 0, MAKELONG(rc.left, rc.top));

                    hr = S_OK;
                }
            }
        }
    }

    if (hr != S_OK)
        hr = SUPERCLASS::TranslateAcceleratorIO(lpMsg);

    return hr;
}

HRESULT CBrowserBandSite::_TrySetFocusTB(int iDir)
{
    HRESULT hres = S_FALSE;
    if (_hwndTB)
    {
        int cBtns = (int) SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
        if (cBtns > 0)
        {
            // Set focus on tb.  This will also set the first button to hottracked,
            // generating a hot item change notify, but _OnHotItemChange will ignore
            // the notify as neither HICF_RESELECT, HICF_ARROWKEYS nor HICF_ACCELERATOR will be set.
            SetFocus(_hwndTB);

            // If going back, make rightmost button hottracked,
            // else make first button hottracked.
            int iHotPos = (iDir == -1) ? cBtns - 1 : 0;

            // Pass HICF_RESELECT so that if we're reselecting the same item, another notify
            // is generated, and so that the filter in _OnHotItemChange will let the notification
            // through (and pop down the chevron menu if necessary).
            SendMessage(_hwndTB, TB_SETHOTITEM2, iHotPos, HICF_RESELECT);

            hres = S_OK;
        }
    }
    return hres;
}

HRESULT CBrowserBandSite::_CycleFocusBS(LPMSG lpMsg)
{
    //
    // Tab order goes: (out)->_hwndOptionsTB->bands->(out)
    //
    // The order is reversed when shift is pressed.
    // 
    // When control is pressed, and we have focus (i.e., have already been tabbed
    // into), we reject focus since ctl-tab is supposed to tab between contexts.
    //
    // Once _hwndOptionsTB gets focus, user can arrow over to _hwndTB.  If
    // that happens, replace _hwndOptionsTB with _hwndTB in order above.
    //

    BOOL fHasFocus = (HasFocusIO() == S_OK);
    ASSERT(fHasFocus || !_ptbActive);

    if (fHasFocus && IsVK_CtlTABCycler(lpMsg))
    {
        // Bail on ctl-tab if one of our guys already has focus
        return S_FALSE;
    }

    HWND hwnd = GetFocus();
    BOOL fHasTBFocus = (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB));
    BOOL fShift = (GetKeyState(VK_SHIFT) < 0);
    HRESULT hres = S_FALSE;

    // hidden options toolbar, bandsite cannot set focus to it (e.g. iBar)
    BOOL fStdExplorerBar = IsWindowVisible(_hwndOptionsTB); 

    if (fHasTBFocus)
    {
        if (!fShift)
            hres = SUPERCLASS::_CycleFocusBS(lpMsg);
    }
    else
    {
        // Here, since !fHasTBFocus, fHasFocus => a band has focus

        if (fHasFocus || fShift || (!fHasFocus && !fStdExplorerBar))
            hres = SUPERCLASS::_CycleFocusBS(lpMsg);

        if (hres != S_OK && (!fHasFocus || (fHasFocus && fShift)))
        {
            // try passing focus to options toolbar if visible;
            if (fStdExplorerBar)
            {
                SetFocus(_hwndOptionsTB);
                TraceMsg(TF_ACCESSIBILITY, "CBrowserBandSite::_CycleFocusBS (hwnd=0x%08X) setting focus to optionsTB (=0x%08X)", _hwnd, _hwndOptionsTB);
                hres = S_OK;
            }
        }
    }

    return hres;
}

// this class subclasses the CBandSite class and adds functionality specific to
// being hosted in the browser....
//
// it implements close as hide 
// it has its own title drawing

void CBrowserBandSite::_OnCloseBand(DWORD dwBandID)
{
    int iIndex = _BandIDToIndex(dwBandID);
    LPBANDITEMDATA pbid = _GetBandItem(iIndex);
    if (pbid)
    {
        _ShowBand(pbid, FALSE);
        if (_pct) 
        {
            BOOL fShowing = FALSE;

            for (int i = _GetBandItemCount() - 1; i >= 0; i--)
            {
                LPBANDITEMDATA pbid = _GetBandItem(i);
                if (pbid)
                {
                    fShowing |= pbid->fShow;
                }
            }    
            if (!fShowing)
            {
                _pct->Exec(&CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
            }
        }
    }
}

// don't allow d/d of any band in here
LRESULT CBrowserBandSite::_OnBeginDrag(NMREBAR* pnm)
{
    return 1;
}

CBrowserBandSite::CBrowserBandSite() : CBandSite(NULL)
{
    _dwBandIDCur = -1;
}

CBrowserBandSite::~CBrowserBandSite()
{
    ATOMICRELEASE(_pCmdTarget);
}


HFONT CBrowserBandSite::_GetTitleFont(BOOL fForceRefresh)
{
    if (_hfont && fForceRefresh)
        DeleteObject(_hfont);

    if (!_hfont || fForceRefresh) {
        // create our font to use for title & toolbar text
        // use A version for win9x compat
        NONCLIENTMETRICSA ncm;

        ncm.cbSize = sizeof(ncm);
        SystemParametersInfoA(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);

        if (!(_dwMode & DBIF_VIEWMODE_VERTICAL)) {
            // horizontal band w/ vertical caption, so rotate the font
            ncm.lfMenuFont.lfEscapement = 900;  // rotate by 90 degrees
            ncm.lfMenuFont.lfOutPrecision = OUT_TT_ONLY_PRECIS; // TT can be rotated
        }

        _hfont = CreateFontIndirectA(&ncm.lfMenuFont);
    }

    return _hfont;
}

void CBrowserBandSite::_InitLayout()
{
    // force update font
    _GetTitleFont(TRUE);
 
    // update toolbar font
    _UpdateToolbarFont();

    // recalc title and toolbar heights
    _CalcHeights();

    _UpdateLayout();
}

void CBrowserBandSite::_UpdateAllBands(BOOL fBSOnly, BOOL fNoAutoSize)
{
    if (!fBSOnly && !fNoAutoSize)
        _InitLayout();

    SUPERCLASS::_UpdateAllBands(fBSOnly, fNoAutoSize);
}

HRESULT CBrowserBandSite::_Initialize(HWND hwndParent)
{
    HRESULT hres = SUPERCLASS::_Initialize(hwndParent);
    SendMessage(_hwnd, CCM_SETUNICODEFORMAT, DLL_IS_UNICODE, 0);

    _CreateOptionsTB();
    _InitLayout();

    return hres;
}

void CBrowserBandSite::_CalcHeights()
{
    // calc title height
    // calc height of captionless bandsites, too, needed to calc toolband height
    // HACKHACK: use height of 'All Folders' as standard title height
    TCHAR szTitle[64];

    if (MLLoadStringW(IDS_TREETITLE, szTitle, ARRAYSIZE(szTitle))) {
        HDC hdc = GetDC(_hwnd);

        if (hdc)
        {
            HFONT hfont = _GetTitleFont(FALSE);
            HFONT hfontOld = (HFONT)SelectObject(hdc, hfont);

            int iLen = lstrlen(szTitle);

            SIZE size;
            GetTextExtentPoint32(hdc, szTitle, iLen, &size);
            _uTitle = size.cy;

            // make space for etch line + space
            _uTitle += CY_ETCH + CY_FLUFF;

            SelectObject(hdc, hfontOld);

            ReleaseDC(_hwnd, hdc);
        }
    } else {
        // no string; use a default height
        _uTitle = BROWSERBAR_TITLEHEIGHT;
    }

    // calc toolbar height
    _uToolbar = _uTitle + (2 * CY_TBPADDING) + CY_ETCH;

    if (_dwStyle & BSIS_NOCAPTION)
    {
        // rebar has no caption
        _uTitle = 0;
    }
}

void CBrowserBandSite::_UpdateToolbarFont()
{
    if (_hwndTB && (_dwMode & DBIF_VIEWMODE_VERTICAL)) {
        // use same font for title and toolbar
        HFONT hfont = _GetTitleFont(FALSE);
        if (hfont)
            SendMessage(_hwndTB, WM_SETFONT, (WPARAM)hfont, TRUE);
    }
}

void CBrowserBandSite::_ShowBand(LPBANDITEMDATA pbid, BOOL fShow)
{
    if (fShow && (_dwBandIDCur != pbid->dwBandID)) {
        _dwBandIDCur = pbid->dwBandID;
        _UpdateLayout();
    } else if (!fShow && _dwBandIDCur == pbid->dwBandID) {
        _dwBandIDCur = -1;
    }

    SUPERCLASS::_ShowBand(pbid, fShow);
}

void CBrowserBandSite::_UpdateLayout()
{
    // update toolbar button size
    if (_hwndTB && SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0) > 0)
    {
        // try to set button height to title height
        LONG lSize = MAKELONG(0, _uTitle);
        SendMessage(_hwndTB, TB_SETBUTTONSIZE, 0, lSize);

        // see what toolbar actually gave us
        RECT rc;
        SendMessage(_hwndTB, TB_GETITEMRECT, 0, (LPARAM)&rc);

        // calc toolbar height (final version)
        _uToolbar = RECTHEIGHT(rc) + CY_ETCH + 2 * CY_TBPADDING;
    }

    // update header height for the current band
    if (_dwBandIDCur != -1)
    {
        REBARBANDINFO rbbi;
        rbbi.cbSize = sizeof(rbbi);
        rbbi.fMask = RBBIM_HEADERSIZE;
        rbbi.cxHeader = _uTitle + (_fToolbar ? _uToolbar : 0);
        SendMessage(_hwnd, RB_SETBANDINFO, _BandIDToIndex(_dwBandIDCur), (LPARAM)&rbbi);
    }

    // update toolbar size
    _UpdateToolbarBand();

    // reposition toolbars
    _PositionToolbars(NULL);
}

void CBrowserBandSite::_BandInfoFromBandItem(REBARBANDINFO *prbbi, LPBANDITEMDATA pbid, BOOL fBSOnly)
{
    SUPERCLASS::_BandInfoFromBandItem(prbbi, pbid, fBSOnly);
    if (prbbi) 
    {
        // we override header width so we can fit browbs's fancy ui (title,
        // toolbar, close & autohide buttons) in the band's header area.
        prbbi->cxHeader = _uTitle + (_fToolbar ? _uToolbar : 0);
    }
}

void CBrowserBandSite::_DrawEtchline(HDC hdc, LPRECT prc, int iOffset, BOOL fVertEtch)
{
    RECT rc;
    CopyRect(&rc, prc);

    if (fVertEtch) {
        rc.left += iOffset - CY_ETCH;
        rc.right = rc.left + 1;
    } else {
        rc.top += iOffset - CY_ETCH;
        rc.bottom = rc.top + 1;
    }
    SHFillRectClr(hdc, &rc, GetSysColor(COLOR_BTNSHADOW));

    if (fVertEtch) {
        rc.left++;
        rc.right++;
    } else {
        rc.bottom++;
        rc.top++;
    }
    SHFillRectClr(hdc, &rc, GetSysColor(COLOR_BTNHILIGHT));
}

LRESULT CBrowserBandSite::_OnCDNotify(LPNMCUSTOMDRAW pnm)
{
    switch (pnm->dwDrawStage) {
    case CDDS_PREPAINT:
        return CDRF_NOTIFYITEMDRAW;

    case CDDS_PREERASE:
        return CDRF_NOTIFYITEMDRAW;

    case CDDS_ITEMPREPAINT:
        if (!(_dwStyle & BSIS_NOCAPTION))
        {
            // horz bar has vert caption and vice versa
            BOOL fVertCaption = (_dwMode&DBIF_VIEWMODE_VERTICAL) ? FALSE:TRUE;
        
            LPBANDITEMDATA pbid = (LPBANDITEMDATA)pnm->lItemlParam;
            if (pbid) 
            {
                int iLen;
                HFONT hfont, hfontOld = NULL;
                LPCTSTR pszTitle;
                SIZE size;
                USES_CONVERSION;

                hfont = _GetTitleFont(FALSE);
                hfontOld = (HFONT)SelectObject(pnm->hdc, hfont);
                pszTitle = W2CT(pbid->szTitle);
                iLen = lstrlen(pszTitle);
                GetTextExtentPoint32(pnm->hdc, pszTitle, iLen, &size);

                // center text inside caption and draw edge at bottom/right.
                if (!fVertCaption) 
                {
                    // vertical bar, has horizontal text
                    int x = pnm->rc.left + CX_TEXTOFFSET;
                    int y = pnm->rc.top + ((_uTitle - CY_ETCH) - size.cy) / 2;
                    ExtTextOut(pnm->hdc, x, y, NULL, NULL, pszTitle, iLen, NULL);

                    _DrawEtchline(pnm->hdc, &pnm->rc, RECTHEIGHT(pnm->rc), fVertCaption);
                    if (_fToolbar)
                        _DrawEtchline(pnm->hdc, &pnm->rc, _uTitle, fVertCaption);
                }
                else 
                {
                    // horizontal bar, has vertical text
                    UINT nPrevAlign = SetTextAlign(pnm->hdc, TA_BOTTOM);
                    int x = pnm->rc.right - ((_uTitle - CY_ETCH) - size.cy) / 2;
                    int y = pnm->rc.bottom - CY_TEXTOFFSET;
                    ExtTextOut(pnm->hdc, x, y, NULL, NULL, pszTitle, iLen, NULL);
                    SetTextAlign(pnm->hdc, nPrevAlign);

                    _DrawEtchline(pnm->hdc, &pnm->rc, RECTWIDTH(pnm->rc), fVertCaption);
                    ASSERT(!_fToolbar);
                }

                if (hfontOld)
                    SelectObject(pnm->hdc, hfontOld);
            }
        }
        return CDRF_SKIPDEFAULT;
    }
    return CDRF_DODEFAULT;
}

LRESULT CBrowserBandSite::_OnNotify(LPNMHDR pnm)
{
    switch (pnm->idFrom) 
    {
    case FCIDM_REBAR:
        switch (pnm->code) 
        {
        case NM_CUSTOMDRAW:
            return _OnCDNotify((LPNMCUSTOMDRAW)pnm);

        case NM_NCHITTEST:
            {
                NMMOUSE *pnmMouse = (NMMOUSE*)pnm;
                RECT rc;
                GetClientRect(_hwnd, &rc);
                if (pnmMouse->dwItemSpec == (DWORD)-1) {
Lchktrans:      
                    //
                    // Edges are mirrored if the window is mirrored. [samera]
                    //
                    if (IS_WINDOW_RTL_MIRRORED(_hwnd)) {
                        int iTmp = rc.right;
                        rc.right = rc.left;
                        rc.left  = iTmp;
                    }

                    // gotta check all 4 edges or non-left-side bars (e.g.
                    // commbar) won't work.
                    // (we separate this into 2 checks to give a trace,
                    // since the old code only checked the right side)
                    if (pnmMouse->pt.x > rc.right)  {
                        return HTTRANSPARENT;
                    }
                    if (pnmMouse->pt.x < rc.left ||
                        pnmMouse->pt.y > rc.bottom || pnmMouse->pt.y < rc.top) {
                        return HTTRANSPARENT;
                    }
                } else if (pnmMouse->dwHitInfo == RBHT_CLIENT) {
                    InflateRect(&rc, -(GetSystemMetrics(SM_CXFRAME)),
                        -(GetSystemMetrics(SM_CYFRAME)));
                    goto Lchktrans;
                }

                return SUPERCLASS::_OnNotify(pnm);
            }

        default:
            return SUPERCLASS::_OnNotify(pnm);
        }

    default:
        return SUPERCLASS::_OnNotify(pnm);
    }

    return 0;
}


IDropTarget* CBrowserBandSite::_WrapDropTargetForBand(IDropTarget* pdtBand)
{
    pdtBand->AddRef();
    return pdtBand;
}


HRESULT CBrowserBandSite::v_InternalQueryInterface(REFIID riid, void **ppv)
{
    static const QITAB qit[] = {
        QITABENT(CBrowserBandSite, IExplorerToolbar),
        { 0 },
    };
    HRESULT hr;
    if (IsEqualIID(riid, IID_IDropTarget))
    {
        *ppv = NULL;
        hr = E_NOINTERFACE;
    }
    else
    {
        hr = QISearch(this, qit, riid, ppv);
        if (FAILED(hr))
            hr = SUPERCLASS::v_InternalQueryInterface(riid, ppv);
    }
    return hr;
}


DWORD CBrowserBandSite::_GetWindowStyle(DWORD *pdwExStyle)
{
    *pdwExStyle = 0;
    return RBS_REGISTERDROP |
            RBS_VERTICALGRIPPER | 
            RBS_VARHEIGHT | RBS_DBLCLKTOGGLE |
            WS_VISIBLE |  WS_CHILD | WS_CLIPCHILDREN | WS_BORDER |
            WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN;
}

// *** IOleCommandTarget ***

HRESULT CBrowserBandSite::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt,
                        VARIANTARG *pvarargIn, VARIANTARG *pvarargOut)
{
    if (pguidCmdGroup == NULL) 
    {
        
    } 
#ifdef UNIX
    // IEUNIX: Special case to handle the case where the band wants to
    // close itself. Used in Cache Warning pane (msgband.cpp)
    else if (IsEqualGUID(CGID_Explorer, *pguidCmdGroup)) 
    {
        switch (nCmdID) 
        {
        case SBCMDID_MSGBAND: 
            {
                IDockingWindow * pdw;
                if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IDockingWindow, &pdw)))) 
                {
                    pdw->ShowDW((BOOL)nCmdexecopt);
                    pdw->Release();
                }
            }
        }
    }
#endif
    else if (IsEqualGUID(CGID_Theater, *pguidCmdGroup)) 
    {
        switch (nCmdID) 
        {
        case THID_ACTIVATE:
            _fTheater = TRUE;
            SHSetWindowBits(_hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, 0);
            // fall through
        case THID_SETBROWSERBARAUTOHIDE:
            if (pvarargIn && pvarargIn->vt == VT_I4)
                _fNoAutoHide = !(pvarargIn->lVal);
            SendMessage(_hwndOptionsTB, TB_CHANGEBITMAP, IDM_AB_AUTOHIDE, _fNoAutoHide ? 2 : 0);
            break;

        case THID_DEACTIVATE:
            _fTheater = FALSE;
            SHSetWindowBits(_hwnd, GWL_EXSTYLE, WS_EX_CLIENTEDGE, WS_EX_CLIENTEDGE);
            break;
        }
        SetWindowPos(_hwnd, NULL, 0,0,0,0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER | SWP_FRAMECHANGED);
        _SizeOptionsTB();

        return S_OK;
    }

    return SUPERCLASS::Exec(pguidCmdGroup, nCmdID, nCmdexecopt, pvarargIn, pvarargOut);
}

#define BBSC_REBAR      0x00000001
#define BBSC_TOOLBAR    0x00000002

void CBrowserBandSite::_CreateTBRebar()
{
    ASSERT(!_hwndTBRebar);

    _hwndTBRebar = CreateWindowEx(WS_EX_TOOLWINDOW, REBARCLASSNAME, NULL,
                           WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN |
                           WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN,
                           0, 0, 100, 36,
                           _hwnd, (HMENU) BBSC_REBAR, HINST_THISDLL, NULL);

    if (_hwndTBRebar)
        SendMessage(_hwndTBRebar, CCM_SETVERSION, COMCTL32_VERSION, 0);
}

void CBrowserBandSite::_InsertToolbarBand()
{
    if (_hwndTBRebar && _hwndTB)
    {
        // Assert that we haven't added the toolbar band yet
        ASSERT(SendMessage(_hwndTBRebar, RB_GETBANDCOUNT, 0, 0) == 0);

        // Assert that we've calculated toolbar height
        ASSERT(_uToolbar);

        REBARBANDINFO rbbi;
        rbbi.cbSize = sizeof(REBARBANDINFO);
        rbbi.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE;

        // RBBIM_CHILD
        rbbi.hwndChild = _hwndTB;

        // RBBIM_CHILDSIZE
        rbbi.cxMinChild = 0;
        rbbi.cyMinChild = _uToolbar - (CY_ETCH + 2 * CY_TBPADDING);

        // RBBIM_STYLE
        rbbi.fStyle = RBBS_NOGRIPPER | RBBS_USECHEVRON;

        SendMessage(_hwndTBRebar, RB_INSERTBAND, -1, (LPARAM)&rbbi);
    }
}

void CBrowserBandSite::_UpdateToolbarBand()
{
    if (_hwndTBRebar && _hwndTB)
    {
        // Assert that we've added the toolbar band
        ASSERT(SendMessage(_hwndTBRebar, RB_GETBANDCOUNT, 0, 0) == 1);

        // Assert that we've calculated toolbar height
        ASSERT(_uToolbar);

        REBARBANDINFO rbbi;
        rbbi.cbSize = sizeof(REBARBANDINFO);
        rbbi.fMask = RBBIM_CHILDSIZE;

        SIZE size = {0, _uToolbar};
        if (SendMessage(_hwndTB, TB_GETIDEALSIZE, FALSE, (LPARAM)&size))
        {
            // RBBIM_IDEALSIZE
            rbbi.fMask |= RBBIM_IDEALSIZE;
            rbbi.cxIdeal = size.cx;
        }

        // RBBIM_CHILDSIZE
        rbbi.cxMinChild = 0;
        rbbi.cyMinChild = _uToolbar - (CY_ETCH + 2 * CY_TBPADDING);

        SendMessage(_hwndTBRebar, RB_SETBANDINFO, 0, (LPARAM)&rbbi);
    }
}

void CBrowserBandSite::_CreateTB()
{
    ASSERT(!_hwndTB);

    // Create a rebar too so we get the chevron
    _CreateTBRebar();

    if (_hwndTBRebar)
    {
        _hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
                        WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS |
                        TBSTYLE_FLAT | TBSTYLE_LIST | CCS_NODIVIDER | CCS_NOPARENTALIGN | CCS_NORESIZE,
                        0, 0, 0, 0,
                        _hwndTBRebar, (HMENU) BBSC_TOOLBAR, HINST_THISDLL, NULL);
    }

    if (_hwndTB)
    {
        SendMessage(_hwndTB, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
        SendMessage(_hwndTB, CCM_SETVERSION, COMCTL32_VERSION, 0);

        // FEATURE: use TBSTYLE_EX_HIDECLIPPEDBUTTONS here?  looks kinda goofy so i'm leaving it out for now.
        SendMessage(_hwndTB, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS | TBSTYLE_EX_MIXEDBUTTONS);

        SendMessage(_hwndTB, TB_SETMAXTEXTROWS, 1, 0L);

        _UpdateToolbarFont();

        _InsertToolbarBand();
    }
}

void CBrowserBandSite::_RemoveAllButtons()
{
    if (!_hwndTB || !_hwndTBRebar)
        return;

    ShowWindow(_hwndTBRebar, SW_HIDE);
    _fToolbar = FALSE;

    INT_PTR nCount = SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0L);
    while (nCount-- > 0)
        SendMessage(_hwndTB, TB_DELETEBUTTON, nCount, 0L);

    _UpdateLayout();
}

void CBrowserBandSite::_Close()
{
    ATOMICRELEASE(_pCmdTarget);

    //
    // Destroying _hwndTBRebar will take care of _hwndTB too
    //
    ASSERT(!_hwndTB || IsChild(_hwndTBRebar, _hwndTB));

    DESTROY_OBJ_WITH_HANDLE(_hwndTBRebar, DestroyWindow);
    DESTROY_OBJ_WITH_HANDLE(_hwndOptionsTB, DestroyWindow);

    DESTROY_OBJ_WITH_HANDLE(_hfont, DeleteObject);

    SUPERCLASS::_Close();
}

LRESULT CBrowserBandSite::_OnHotItemChange(LPNMTBHOTITEM pnmtb)
{
    LRESULT lres = 0;

    // We might want to drop down the chevron menu if the hot item change
    // flags has these characteristics:
    //
    //  - not HICF_LEAVING, since if HICF_LEAVING, the hot item should instead wrap to _hwndClose
    //  - and not HICF_MOUSE, since we only drop down on keyboard hot item change
    //  - HICF_ACCELERATOR | HICF_ARROWKEYS, since we only drop down on keyboard hot item change
    //  - or HICF_RESELECT, since we force a reselect in _TrySetFocusTB
    //
    if (!(pnmtb->dwFlags & (HICF_LEAVING | HICF_MOUSE)) &&
        (pnmtb->dwFlags & (HICF_RESELECT | HICF_ACCELERATOR | HICF_ARROWKEYS)))
    {
        // Check to see if new hot button is clipped.  If it is,
        // then we pop down the chevron menu.
        RECT rc;
        GetClientRect(_hwndTB, &rc);

        int iButton = (int)SendMessage(_hwndTB, TB_COMMANDTOINDEX, pnmtb->idNew, 0);

        if (SHIsButtonObscured(_hwndTB, &rc, iButton))
        {
            // Clear hot item
            SendMessage(_hwndTB, TB_SETHOTITEM, -1, 0);

            // Figure out whether to highlight first or last item in menu
            UINT uSelect;
            int cButtons = (int)SendMessage(_hwndTB, TB_BUTTONCOUNT, 0, 0);
            if (iButton == cButtons - 1)
                uSelect = DBPC_SELECTLAST;
            else
                uSelect = DBPC_SELECTFIRST;

            // Pop it down
            SendMessage(_hwndTBRebar, RB_PUSHCHEVRON, 0, uSelect);

            lres = 1;
        }
    }

    return lres;
}

LRESULT CBrowserBandSite::_OnNotifyBBS(LPNMHDR pnm)
{
    switch (pnm->code)
    {
    case TBN_DROPDOWN:
        if (EVAL(_pCmdTarget))
        {
            LPNMTOOLBAR pnmtoolbar = (LPNMTOOLBAR)pnm;
            VARIANTARG  var;
            RECT rc = pnmtoolbar->rcButton;
            
            var.vt = VT_I4;
            MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
            var.lVal = MAKELONG(rc.left, rc.bottom);
            
            _pCmdTarget->Exec(&_guidButtonGroup, pnmtoolbar->iItem, OLECMDEXECOPT_PROMPTUSER, &var, NULL);
        }
        break;

    case TBN_WRAPHOTITEM:
        {
            LPNMTBWRAPHOTITEM pnmwh = (LPNMTBWRAPHOTITEM) pnm;

            if (pnmwh->nReason & HICF_ARROWKEYS) {
                if (pnm->hwndFrom == _hwndOptionsTB) {
                    if (_TrySetFocusTB(pnmwh->iDir) != S_OK)
                        return 0;
                } else {
                    ASSERT(pnm->hwndFrom == _hwndTB);
                    SetFocus(_hwndOptionsTB);
                }
                return 1;
            }
        }
        break;

    case TBN_HOTITEMCHANGE:
        if (pnm->hwndFrom == _hwndTB)
            return _OnHotItemChange((LPNMTBHOTITEM)pnm);
        break;

    case TBN_GETINFOTIP:
        //  [scotthan] We'll ask the toolbar owner for tip text via
        //  IOleCommandTarget::QueryStatus, like we do w/ defview for itbar buttons
        if (_pCmdTarget && pnm->hwndFrom == _hwndTB)
        {
            NMTBGETINFOTIP* pgit = (NMTBGETINFOTIP*)pnm ;

            OLECMDTEXTV<MAX_TOOLTIP_STRING> cmdtv;
            OLECMDTEXT *pcmdText = &cmdtv;
 
            pcmdText->cwBuf    = MAX_TOOLTIP_STRING;
            pcmdText->cmdtextf = OLECMDTEXTF_NAME;
            pcmdText->cwActual = 0;
 
            OLECMD rgcmd = {pgit->iItem, 0};
 
            HRESULT hr = _pCmdTarget->QueryStatus(&_guidButtonGroup, 1, &rgcmd, pcmdText);
            if (SUCCEEDED(hr) && (pcmdText->cwActual))
            {
                SHUnicodeToTChar(pcmdText->rgwz, pgit->pszText, pgit->cchTextMax);
                return 1;
            }
        }
        break ;

    case RBN_CHEVRONPUSHED:
        LPNMREBARCHEVRON pnmch = (LPNMREBARCHEVRON) pnm;

        MapWindowPoints(pnmch->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&pnmch->rc, 2);
        ToolbarMenu_Popup(_hwnd, &pnmch->rc, NULL, _hwndTB, 0, (DWORD)pnmch->lParamNM);

        return 1;
    }

    return 0;
}

// *** IWinEventHandler ***
HRESULT CBrowserBandSite::OnWinEvent(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT *plres)
{
    switch (uMsg)
    {
    case WM_COMMAND:
        {
            HWND hwndControl = GET_WM_COMMAND_HWND(wParam, lParam);
            UINT idCmd = GET_WM_COMMAND_ID(wParam, lParam);

            if (hwndControl && hwndControl == _hwndTB)
            {
                if (EVAL(_pCmdTarget))
                {
                    RECT rc;
                    VARIANTARG var;

                    var.vt = VT_I4;
                    SendMessage(_hwndTB, TB_GETRECT, idCmd, (LPARAM)&rc);
                    MapWindowPoints(_hwndTB, HWND_DESKTOP, (LPPOINT)&rc, 2);
                    var.lVal = MAKELONG(rc.left, rc.bottom);

                    _pCmdTarget->Exec(&_guidButtonGroup, idCmd, 0, &var, NULL);
                }
                return S_OK;
            }
            else if (hwndControl == _hwndOptionsTB) {
                switch (idCmd) {
                case IDM_AB_CLOSE:
                    IUnknown_Exec(_punkSite, &CGID_DeskBarClient, DBCID_EMPTY, 0, NULL, NULL);
                    break;

                case IDM_AB_AUTOHIDE:
                    { 
                        VARIANTARG v = {0};
                        v.vt = VT_I4;
                        v.lVal = _fNoAutoHide;
                        IUnknown_Exec(_punkSite, &CGID_Theater, THID_SETBROWSERBARAUTOHIDE, 0, &v, NULL);

                        break;
                    }
                }
                return S_OK;
            }
        }
        break;

    case WM_NOTIFY:
        {
            LPNMHDR pnm = (LPNMHDR)lParam;
            if (pnm && (pnm->hwndFrom == _hwndTB || pnm->hwndFrom == _hwndOptionsTB || pnm->hwndFrom == _hwndTBRebar)) {
                *plres = _OnNotifyBBS(pnm);
                return S_OK;
            }
        }
        break;

    case WM_SIZE:
        {
            POINT pt = {LOWORD(lParam), HIWORD(lParam)};
            _PositionToolbars(&pt);
        }
        break;
    }

    return SUPERCLASS::OnWinEvent(hwnd, uMsg, wParam, lParam, plres);
}

HRESULT CBrowserBandSite::IsWindowOwner(HWND hwnd)
{
    if (hwnd && (hwnd == _hwndTB) || (hwnd == _hwndOptionsTB) || (hwnd == _hwndTBRebar))
        return S_OK;

    return SUPERCLASS::IsWindowOwner(hwnd);
}

// *** IBandSite ***
HRESULT CBrowserBandSite::SetBandSiteInfo(const BANDSITEINFO * pbsinfo)
{
    // recompute our layout if vertical viewmode is changing
    BOOL fUpdate = ((pbsinfo->dwMask & BSIM_STATE) && 
                    ((pbsinfo->dwState ^ _dwMode) & DBIF_VIEWMODE_VERTICAL));
    // ...or if caption is turned on or off
    BOOL fCaptionStyleChanged = (   (pbsinfo->dwMask & BSIM_STYLE)
                                 && ((pbsinfo->dwStyle ^ _dwStyle) & BSIS_NOCAPTION));

    HRESULT hres = SUPERCLASS::SetBandSiteInfo(pbsinfo);

    if (fCaptionStyleChanged && _hwndOptionsTB)
    {
        if (_fToolbar) {
            // don't know if "new" band requires buttons or not, expect band to add buttons again if needed
            _RemoveAllButtons();
        }
        // show or hide close/hide toolbar; is always created since bandsites get reused!
        ::ShowWindow(_hwndOptionsTB, (_dwStyle & BSIS_NOCAPTION) ? SW_HIDE : SW_SHOW);
    }

    if (fUpdate || fCaptionStyleChanged) {
        _InitLayout();
    }

    return hres;
}


// *** IExplorerToolbar ***
HRESULT CBrowserBandSite::SetCommandTarget(IUnknown* punkCmdTarget, const GUID* pguidButtonGroup, DWORD dwFlags)
{
    HRESULT hres = S_OK;
    BOOL fRemoveButtons = TRUE;

    // dwFlags is not used
    ASSERT(!(dwFlags));

    ATOMICRELEASE(_pCmdTarget);
    if (punkCmdTarget && pguidButtonGroup)
    {
        hres = punkCmdTarget->QueryInterface(IID_IOleCommandTarget, (void**)&(_pCmdTarget));

        if (!_hwndTB)
        {
            _CreateTB();
        }
        else if (_fToolbar && IsEqualGUID(_guidButtonGroup, *pguidButtonGroup))
        {
            fRemoveButtons = FALSE;
            hres = S_FALSE;
        }

        _guidButtonGroup = *pguidButtonGroup;
    }
    else
        ASSERT(!punkCmdTarget);

    if (fRemoveButtons)
        _RemoveAllButtons();

    ASSERT(SUCCEEDED(hres));
    return hres;
}

// client should have already called AddString
HRESULT CBrowserBandSite::AddButtons(const GUID* pguidButtonGroup, UINT nButtons, const TBBUTTON* lpButtons)
{
    if (!_hwndTB || !nButtons)
        return E_FAIL;

    _RemoveAllButtons();

    if (SendMessage(_hwndTB, TB_ADDBUTTONS, nButtons, (LPARAM)lpButtons))
    {
        ShowWindow(_hwndTBRebar, SW_SHOW);
        _fToolbar = TRUE;

        _UpdateLayout();

        return S_OK;
    }

    return E_FAIL;
}

HRESULT CBrowserBandSite::AddString(const GUID* pguidButtonGroup, HINSTANCE hInst, UINT_PTR uiResID, LRESULT* pOffset)
{
    *pOffset = -1;
    if (!_hwndTB)
        return E_FAIL;

    *pOffset = SendMessage(_hwndTB, TB_ADDSTRING, (WPARAM)hInst, (LPARAM)uiResID);

    if (*pOffset != -1)
        return S_OK;

    return E_FAIL;
}

HRESULT CBrowserBandSite::GetButton(const GUID* pguidButtonGroup, UINT uiCommand, LPTBBUTTON lpButton)
{
    if (!_hwndTB)
        return E_FAIL;

    UINT_PTR uiIndex = SendMessage(_hwndTB, TB_COMMANDTOINDEX, uiCommand, 0L);
    if (SendMessage(_hwndTB, TB_GETBUTTON, uiIndex, (LPARAM)lpButton))
        return S_OK;

    return E_FAIL;
}

HRESULT CBrowserBandSite::GetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT* pfState)
{
    if (!_hwndTB)
        return E_FAIL;

    *pfState = (UINT)SendMessage(_hwndTB, TB_GETSTATE, uiCommand, 0L);
    return S_OK;
}

HRESULT CBrowserBandSite::SetState(const GUID* pguidButtonGroup, UINT uiCommand, UINT fState)
{
    if (!_hwndTB)
        return E_FAIL;

    UINT_PTR uiState = SendMessage(_hwndTB, TB_GETSTATE, uiCommand, NULL);
    uiState ^= fState;
    if (uiState)
        SendMessage(_hwndTB, TB_SETSTATE, uiCommand, (LPARAM)fState);

    return S_OK;
}

HRESULT CBrowserBandSite::SetImageList( const GUID* pguidCmdGroup, HIMAGELIST himlNormal, HIMAGELIST himlHot, HIMAGELIST himlDisabled)
{
    if (IsEqualGUID(*pguidCmdGroup, _guidButtonGroup)) {
        SendMessage(_hwndTB, TB_SETIMAGELIST, 0, (LPARAM)himlNormal);
        SendMessage(_hwndTB, TB_SETHOTIMAGELIST, 0, (LPARAM)himlHot);
        SendMessage(_hwndTB, TB_SETDISABLEDIMAGELIST, 0, (LPARAM)himlDisabled);
    }
    return S_OK;
};

BYTE TBStateFromIndex(HWND hwnd, int iIndex)
{
    TBBUTTONINFO tbbi;
    tbbi.cbSize = sizeof(TBBUTTONINFO);
    tbbi.dwMask = TBIF_BYINDEX | TBIF_STATE;
    tbbi.fsState = 0;
    SendMessage(hwnd, TB_GETBUTTONINFO, iIndex, (LPARAM)&tbbi);

    return tbbi.fsState;
}

int CBrowserBandSite::_ContextMenuHittest(LPARAM lParam, POINT* ppt)
{
    if (lParam == (LPARAM)-1)
    {
        //
        // Keyboard activation.  If one of our toolbars has
        // focus, and it has a hottracked button, put up the
        // context menu below that button.
        //
        HWND hwnd = GetFocus();
        if (hwnd && (hwnd == _hwndTB || hwnd == _hwndOptionsTB))
        {
            INT_PTR iHot = SendMessage(hwnd, TB_GETHOTITEM, 0, 0);
            if (iHot == -1)
            {
                // couldn't find a hot item, just use the first visible button
                iHot = 0;
                while (TBSTATE_HIDDEN & TBStateFromIndex(hwnd, (int)iHot))
                    iHot++;

                ASSERT(iHot < SendMessage(hwnd, TB_BUTTONCOUNT, 0, 0));
            }

            RECT rc;
            SendMessage(hwnd, TB_GETITEMRECT, iHot, (LPARAM)&rc);

            ppt->x = rc.left;
            ppt->y = rc.bottom;

            MapWindowPoints(hwnd, HWND_DESKTOP, ppt, 1);

            return -1;
        }
    }

    return SUPERCLASS::_ContextMenuHittest(lParam, ppt);
}

HMENU CBrowserBandSite::_LoadContextMenu()
{
    HMENU hmenu = SUPERCLASS::_LoadContextMenu();
    DeleteMenu(hmenu, BSIDM_SHOWTITLEBAND, MF_BYCOMMAND);
    return hmenu;
}

// create the options (close/hide) buttons
void CBrowserBandSite::_CreateOptionsTB()
{
    // create toolbar for close/hide button always since band site is reused
    // for captionless band sites (iBar), this toolbar is only hidden
    _hwndOptionsTB = CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
                                WS_VISIBLE | 
                                WS_CHILD | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS |
                                WS_CLIPCHILDREN |
                                WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOMOVEY | CCS_NOPARENTALIGN |
                                CCS_NORESIZE,
                                0, 0, 30, 18, _hwnd, 0, HINST_THISDLL, NULL);

    _PrepareOptionsTB();
}

// init as toolbar and load bitmaps
void CBrowserBandSite::_PrepareOptionsTB()
{
    if (_hwndOptionsTB)
    {
        static const TBBUTTON c_tb[] =
        {
            { 0, IDM_AB_AUTOHIDE, TBSTATE_ENABLED, TBSTYLE_CHECK, {0,0}, 0, 0 },
            { 1, IDM_AB_CLOSE, TBSTATE_ENABLED, TBSTYLE_BUTTON, {0,0}, 0, 1 }
        };

        SendMessage(_hwndOptionsTB, TB_BUTTONSTRUCTSIZE,    sizeof(TBBUTTON), 0);
        SendMessage(_hwndOptionsTB, CCM_SETVERSION, COMCTL32_VERSION, 0);

        SendMessage(_hwndOptionsTB, TB_SETBITMAPSIZE, 0, (LPARAM) MAKELONG(13, 11));
        TBADDBITMAP tbab = { HINST_THISDLL, IDB_BROWSERTOOLBAR };
        SendMessage(_hwndOptionsTB, TB_ADDBITMAP, 3, (LPARAM)&tbab);

        LONG_PTR cbOffset = SendMessage(_hwndOptionsTB, TB_ADDSTRING, (WPARAM)MLGetHinst(), (LPARAM)IDS_BANDSITE_CLOSE_LABELS);
        TBBUTTON tb[ARRAYSIZE(c_tb)];
        UpdateButtonArray(tb, c_tb, ARRAYSIZE(c_tb), cbOffset);

        SendMessage(_hwndOptionsTB, TB_SETMAXTEXTROWS, 0, 0);

        SendMessage(_hwndOptionsTB, TB_ADDBUTTONS, ARRAYSIZE(tb), (LPARAM)tb);

        SendMessage(_hwndOptionsTB, TB_SETINDENT, (WPARAM)0, 0);
        
        _SizeOptionsTB();
    }    
}

void CBrowserBandSite::_PositionToolbars(LPPOINT ppt)
{
    RECT rc;

    if (ppt) 
    {
        rc.left = 0;
        rc.right = ppt->x;
    } 
    else 
    {
        GetClientRect(_hwnd, &rc);
    }

    if (_hwndOptionsTB) 
    {
        // always put the close restore at the top right of the floater window
        int x;

        if (_dwMode & DBIF_VIEWMODE_VERTICAL) 
        {
            RECT rcTB;
            GetWindowRect(_hwndOptionsTB, &rcTB);
            x = rc.right - RECTWIDTH(rcTB) - 1;
        }
        else
        {
            x = rc.left;
        }

        MARGINS mBorders = {0, 1, 0, 0};        // 1 mimics old behavior downlevel.
        Comctl32_GetBandMargins(_hwnd, &mBorders);

        SetWindowPos(_hwndOptionsTB, HWND_TOP, x - mBorders.cxRightWidth, mBorders.cyTopHeight, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
    }

    if (_hwndTBRebar)
    {
        if (_fToolbar) 
        {
            // toolbar goes on its own line below title
            SetWindowPos(_hwndTBRebar, HWND_TOP, 
                            rc.left + CX_TBOFFSET,
                            _uTitle + CX_TBOFFSET,
                            rc.right - 2 * CX_TBOFFSET,
                            _uToolbar,
                            SWP_SHOWWINDOW);

        } 
        else 
        {
            ASSERT(!IsWindowVisible(_hwndTBRebar));
        }
    }
}

// sets the size of the toolbar.  if we're in theater mode, we need to show the pushpin.
// otherwise just show the close
void CBrowserBandSite::_SizeOptionsTB()
{
    RECT rc;
    GetWindowRect(_hwndOptionsTB, &rc);
    LRESULT lButtonSize = SendMessage(_hwndOptionsTB, TB_GETBUTTONSIZE, 0, 0L);
    SetWindowPos(_hwndOptionsTB, NULL, 0, 0, LOWORD(lButtonSize) * (_fTheater ? 2 : 1),
                 RECTHEIGHT(rc), SWP_NOMOVE | SWP_NOACTIVATE);

    DWORD_PTR dwState = SendMessage(_hwndOptionsTB, TB_GETSTATE, IDM_AB_AUTOHIDE, 0);
    dwState &= ~(TBSTATE_HIDDEN | TBSTATE_CHECKED);
    if (!_fTheater)
        dwState |= TBSTATE_HIDDEN;
    if (_fNoAutoHide)
        dwState |= TBSTATE_CHECKED;
    SendMessage(_hwndOptionsTB, TB_SETSTATE, IDM_AB_AUTOHIDE, dwState);
    _PositionToolbars(NULL);
}