windows-nt/Source/XPSP1/NT/shell/cpls/nusrmgr/toolbar.cpp
2020-09-26 16:20:57 +08:00

391 lines
11 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 2001.
//
// File: Toolbar.cpp
//
// Contents: implementation of CToolbar
//
//----------------------------------------------------------------------------
#include "stdafx.h"
#include "Toolbar.h"
class CAppCommandHook
{
public:
static void SetHook(HWND hWnd)
{
CAppCommandHook *pach = _GetInfo(TRUE);
if (pach)
{
if (NULL != pach->_hHook)
{
UnhookWindowsHookEx(pach->_hHook);
pach->_hHook = NULL;
pach->_hWnd = NULL;
}
if (NULL != hWnd)
{
pach->_hWnd = hWnd;
pach->_hHook = SetWindowsHookEx(WH_SHELL, _HookProc, NULL, GetCurrentThreadId());
}
}
}
static void Unhook(void)
{
CAppCommandHook *pach = _GetInfo(FALSE);
if (-1 != g_tlsAppCommandHook)
{
TlsSetValue(g_tlsAppCommandHook, NULL);
}
delete pach;
}
private:
CAppCommandHook() : _hHook(NULL), _hWnd(NULL) {}
~CAppCommandHook()
{
if (NULL != _hHook)
UnhookWindowsHookEx(_hHook);
}
static CAppCommandHook* _GetInfo(BOOL bAlloc)
{
CAppCommandHook *pach = NULL;
if (-1 != g_tlsAppCommandHook)
{
pach = (CAppCommandHook*)TlsGetValue(g_tlsAppCommandHook);
if (NULL == pach && bAlloc)
{
pach = new CAppCommandHook;
if (NULL != pach)
{
TlsSetValue(g_tlsAppCommandHook, pach);
}
}
}
return pach;
}
static LRESULT CALLBACK _HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
CAppCommandHook *pach = _GetInfo(FALSE);
if (pach)
{
if (nCode == HSHELL_APPCOMMAND && NULL != pach->_hWnd)
{
if (::SendMessage(pach->_hWnd, WM_APPCOMMAND, wParam, lParam))
return 0;
}
if (NULL != pach->_hHook)
return CallNextHookEx(pach->_hHook, nCode, wParam, lParam);
}
return 0;
}
private:
HHOOK _hHook;
HWND _hWnd;
};
/////////////////////////////////////////////////////////////////////////////
// CToolbar
LRESULT CToolbar::_OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
m_hAccel = LoadAccelerators(_Module.GetResourceInstance(), MAKEINTRESOURCE(IDR_ACCEL));
DWORD dwExStyle = TBSTYLE_EX_MIXEDBUTTONS;
//
// NTRAID#NTBUG9-300152-2001/02/02-jeffreys Toolbar isn't mirrored
//
// The HTA frame window isn't getting the right layout style on mirrored
// builds. This style is normally inherited from parent to child, so
// we shouldn't have to do anything here.
//
// However, I'm putting this in temporarily so the toolbar will be
// mirrored for beta 2. After beta 2, or whenever trident fixes the
// HTA problem, this can be removed.
//
CComVariant varRTL;
if (SUCCEEDED(GetAmbientProperty(DISPID_AMBIENT_RIGHTTOLEFT, varRTL))
&& varRTL.boolVal == VARIANT_TRUE)
{
dwExStyle |= WS_EX_NOINHERITLAYOUT | WS_EX_LAYOUTRTL;
}
RECT rc = {0,0,0,0};
m_ctlToolbar.Create(m_hWnd,
&rc,
NULL,
WS_CHILD | WS_VISIBLE | CCS_NODIVIDER | CCS_TOP | CCS_NOPARENTALIGN | TBSTYLE_FLAT | TBSTYLE_LIST | TBSTYLE_TOOLTIPS,
dwExStyle);
if (!m_ctlToolbar)
return -1;
m_ctlToolbar.SendMessage(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0);
int idBmp = IDB_NAVBAR;
if (SHGetCurColorRes() > 8)
idBmp += (IDB_NAVBARHICOLOR - IDB_NAVBAR);
m_himlNBDef = ImageList_LoadImageW(_Module.GetResourceInstance(),
MAKEINTRESOURCE(idBmp),
NAVBAR_CX,
0,
CLR_DEFAULT,
IMAGE_BITMAP,
LR_CREATEDIBSECTION);
if (m_himlNBDef)
{
m_ctlToolbar.SendMessage(TB_SETIMAGELIST, 0, (LPARAM)m_himlNBDef);
}
m_himlNBHot = ImageList_LoadImageW(_Module.GetResourceInstance(),
MAKEINTRESOURCE(idBmp+1),
NAVBAR_CX,
0,
CLR_DEFAULT,
IMAGE_BITMAP,
LR_CREATEDIBSECTION);
if (m_himlNBHot)
{
m_ctlToolbar.SendMessage(TB_SETHOTIMAGELIST, 0, (LPARAM)m_himlNBHot);
}
if (!m_himlNBDef && !m_himlNBHot)
{
// Must be serious low memory or other resource problems.
// There's no point having a toolbar without any images.
m_ctlToolbar.DestroyWindow();
return -1;
}
TCHAR szBack[64];
TCHAR szHome[64];
TBBUTTON rgButtons[] =
{
{0, ID_BACK, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szBack},
{1, ID_FORWARD, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE, {0}, 0, 0},
{2, ID_HOME, TBSTATE_ENABLED, BTNS_BUTTON | BTNS_AUTOSIZE | BTNS_SHOWTEXT, {0}, 0, (INT_PTR)szHome},
};
::LoadStringW(_Module.GetResourceInstance(), ID_BACK, szBack, ARRAYSIZE(szBack));
::LoadStringW(_Module.GetResourceInstance(), ID_HOME, szHome, ARRAYSIZE(szHome));
m_ctlToolbar.SendMessage(TB_ADDBUTTONSW, ARRAYSIZE(rgButtons), (LPARAM)rgButtons);
// Update the position and extent stuff. Do this asynchronously since ATL
// will call SetObjectRects shortly after we return from this method (with
// the original rect).
PostMessage(PWM_UPDATESIZE);
// Set a hook to redirect WM_APPCOMMAND messages to our control window
CAppCommandHook::SetHook(m_hWnd);
return 0;
}
LRESULT CToolbar::_OnDestroy(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
CAppCommandHook::Unhook();
return 0;
}
LRESULT CToolbar::_OnAppCommand(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
{
switch (GET_APPCOMMAND_LPARAM(lParam))
{
case APPCOMMAND_BROWSER_BACKWARD:
Fire_OnButtonClick(0);
break;
case APPCOMMAND_BROWSER_FORWARD:
Fire_OnButtonClick(1);
break;
case APPCOMMAND_BROWSER_HOME:
Fire_OnButtonClick(2);
break;
default:
bHandled = FALSE;
break;
}
return 0;
}
LRESULT CToolbar::_UpdateSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_ctlToolbar)
{
//
// TB_AUTOSIZE causes m_ctlToolbar to set its preferred height, but it
// doesn't adjust it's width or position because of the styles we use
// (CCS_TOP | CCS_NOPARENTALIGN).
//
// The width will always be the same as m_rcPos because we keep them
// in sync via SetObjectRects below.
//
// If the height is different after TB_AUTOSIZE, ask the container to
// adjust our rect.
//
m_ctlToolbar.SendMessage(TB_AUTOSIZE, 0, 0);
RECT rc;
m_ctlToolbar.GetWindowRect(&rc);
::MapWindowPoints(NULL, GetParent(), (LPPOINT)&rc, 2);
if ((rc.bottom - rc.top) != (m_rcPos.bottom - m_rcPos.top))
{
//
// We only want to set the height (leave the width alone), but
// OnPosRectChange sets both the height and the width. Moreover,
// it sets the width to a fixed (pixel) width, nuking styles such
// as "100%". We get around this by getting the current width
// now and restoring it after calling OnPosRectChange.
//
CComPtr<IHTMLStyle> spStyle;
CComVariant varWidth;
CComQIPtr<IOleControlSite> spCtrlSite(m_spClientSite);
if (spCtrlSite)
{
CComPtr<IDispatch> spDispatch;
spCtrlSite->GetExtendedControl(&spDispatch);
if (spDispatch)
{
CComQIPtr<IHTMLElement> spElement(spDispatch);
if (spElement)
{
spElement->get_style(&spStyle);
if (spStyle)
{
spStyle->get_width(&varWidth);
}
}
}
}
// Ask the container to give us a new rect
m_spInPlaceSite->OnPosRectChange(&rc);
// Restore the previous width style
if (spStyle)
{
spStyle->setAttribute(L"width", varWidth, 0);
}
}
}
return 0;
}
HRESULT CToolbar::OnAmbientPropertyChange(DISPID dispid)
{
switch (dispid)
{
case DISPID_UNKNOWN:
case DISPID_AMBIENT_FONT:
_ClearAmbientFont();
_GetAmbientFont();
m_ctlToolbar.SendMessage(WM_SETFONT, (WPARAM)m_hFont, FALSE);
m_ctlToolbar.InvalidateRect(NULL); // redraw
break;
}
return S_OK;
}
void CToolbar::_ClearAmbientFont(void)
{
if (m_pFont)
{
if (m_hFont)
m_pFont->ReleaseHfont(m_hFont);
m_pFont->Release();
m_pFont = NULL;
}
m_hFont = NULL;
}
void CToolbar::_GetAmbientFont(void)
{
if (!m_hFont)
{
// Try to get the ambient font from our container
if (SUCCEEDED(GetAmbientFont(&m_pFont)))
{
if (SUCCEEDED(m_pFont->get_hFont(&m_hFont)))
{
// Yea, everybody is happy
m_pFont->AddRefHfont(m_hFont);
}
else
{
// Darn, couldn't get the font from container
_ClearAmbientFont();
}
}
}
}
STDMETHODIMP CToolbar::get_enabled(VARIANT vIndex, VARIANT_BOOL *pVal)
{
if (!pVal)
return E_POINTER;
*pVal = VARIANT_FALSE;
if (FAILED(VariantChangeType(&vIndex, &vIndex, 0, VT_I4)))
return E_INVALIDARG;
LRESULT state = m_ctlToolbar.SendMessage(TB_GETSTATE, ID_BACK + vIndex.lVal, 0);
if (-1 == state)
return E_INVALIDARG;
if (state & TBSTATE_ENABLED)
*pVal = VARIANT_TRUE;
return S_OK;
}
STDMETHODIMP CToolbar::put_enabled(VARIANT vIndex, VARIANT_BOOL newVal)
{
if (FAILED(VariantChangeType(&vIndex, &vIndex, 0, VT_I4)))
return E_INVALIDARG;
m_ctlToolbar.SendMessage(TB_ENABLEBUTTON, ID_BACK + vIndex.lVal, MAKELONG((VARIANT_TRUE == newVal), 0));
return S_OK;
}
void CToolbar::Fire_OnButtonClick(int buttonIndex)
{
int nConnectionIndex;
CComVariant* pvars = new CComVariant[1];
int nConnections = m_vec.GetSize();
for (nConnectionIndex = 0; nConnectionIndex < nConnections; nConnectionIndex++)
{
Lock();
CComPtr<IUnknown> sp = m_vec.GetAt(nConnectionIndex);
Unlock();
IDispatch* pDispatch = reinterpret_cast<IDispatch*>(sp.p);
if (pDispatch != NULL)
{
pvars[0] = buttonIndex;
DISPPARAMS disp = { pvars, NULL, 1, 0 };
pDispatch->Invoke(0x1, IID_NULL, LOCALE_USER_DEFAULT, DISPATCH_METHOD, &disp, NULL, NULL, NULL);
}
}
delete[] pvars;
}