|
|
//+---------------------------------------------------------------------------
//
// 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; }
|