/*++ Copyright (C) 1996-1999 Microsoft Corporation Module Name: colefont.cpp Abstract: Font class. --*/ #include "polyline.h" #include #include "unihelpr.h" #include "winhelpr.h" #include "COleFont.h" #pragma warning ( disable : 4355 ) // "this" used in initializer list const LPWSTR COleFont::m_cwszDefaultFaceName = L"MS Shell Dlg"; const INT COleFont::m_iDefaultTmHeight = 13; const SHORT COleFont::m_iDefaultTmWeight = 400; const INT COleFont::m_iDefaultRiPxlsPerInch = 96; COleFont::COleFont ( CSysmonControl *pCtrl ) : m_NotifySink( this ) { m_pIFont = NULL; m_pIFontBold = NULL; m_pCtrl = pCtrl; m_pIConnPt = NULL; } COleFont::~COleFont ( void ) { // Release current connection point if (m_pIConnPt) { m_pIConnPt->Unadvise(m_dwCookie); ReleaseInterface(m_pIConnPt); } // Release fonts ReleaseInterface(m_pIFont); ReleaseInterface(m_pIFontBold); } void COleFont::InitDefaultFontDesc ( FONTDESC& rFontDesc, INT& riPxlsPerInch, WCHAR achFaceName[LF_FACESIZE+1] ) { TEXTMETRIC TextMetrics; HFONT hFontOld; HDC hDC; // Todo: Must define proper default values, move them to resources // for localization. ZeroMemory ( &rFontDesc, sizeof ( FONTDESC ) ); // Select default font hDC = GetDC(NULL); if ( NULL != hDC ) { hFontOld = SelectFont(hDC, (HFONT)GetStockObject(DEFAULT_GUI_FONT)); // Get face name and size // // TODO: Should we check the return error code here? // GetTextMetrics(hDC, &TextMetrics); GetTextFaceW(hDC, LF_FACESIZE, achFaceName); // Get pixels per inch riPxlsPerInch = GetDeviceCaps(hDC, LOGPIXELSY); // Create a default font rFontDesc.lpstrName = achFaceName; rFontDesc.cySize.int64 = ((TextMetrics.tmHeight * 72) / riPxlsPerInch) * 10000; rFontDesc.sWeight = (short)TextMetrics.tmWeight; SelectFont(hDC, hFontOld); ReleaseDC(NULL, hDC); } else { riPxlsPerInch = m_iDefaultRiPxlsPerInch; StringCchCopy(achFaceName, LF_FACESIZE+1, m_cwszDefaultFaceName); // Create a default font rFontDesc.lpstrName = achFaceName; rFontDesc.cySize.int64 = ((m_iDefaultTmHeight * 72) / m_iDefaultRiPxlsPerInch) * 10000; rFontDesc.sWeight = m_iDefaultTmWeight; } rFontDesc.cbSizeofstruct = sizeof(rFontDesc); rFontDesc.sCharset = DEFAULT_CHARSET; rFontDesc.fItalic = 0; rFontDesc.fUnderline = 0; rFontDesc.fStrikethrough = 0; } HRESULT COleFont::Init ( VOID ) { HRESULT hr; FONTDESC fontDesc; WCHAR achFontFaceName[LF_FACESIZE+1]; LPFONT pIFont; INT iPxlsPerInch; InitDefaultFontDesc ( fontDesc, iPxlsPerInch, achFontFaceName ); hr = OleCreateFontIndirect(&fontDesc, IID_IFont, (void**)&pIFont); if (FAILED(hr)) { return hr; } pIFont->SetRatio(iPxlsPerInch, HIMETRIC_PER_INCH); hr = SetIFont(pIFont); pIFont->Release(); return hr; } STDMETHODIMP COleFont::SetIFont( LPFONT pIFont ) { HRESULT hr; IConnectionPointContainer *pIConnPtCont; IPropertyNotifySink *pISink; // Release current connection point if (m_pIConnPt) { m_pIConnPt->Unadvise(m_dwCookie); ReleaseInterface(m_pIConnPt); } // Release current fonts ClearInterface(m_pIFont); ClearInterface(m_pIFontBold); // Addref and hold new IFont m_pIFont = pIFont; m_pIFont->AddRef(); // Get it's property notify connection point hr = pIFont->QueryInterface(IID_IConnectionPointContainer, (void **)&pIConnPtCont); if (SUCCEEDED(hr)) { hr = pIConnPtCont->FindConnectionPoint(IID_IPropertyNotifySink, &m_pIConnPt); pIConnPtCont->Release(); // Connect our sink to it if (SUCCEEDED(hr)) { m_NotifySink.QueryInterface(IID_IPropertyNotifySink, (void **)&pISink); hr = m_pIConnPt->Advise(pISink, &m_dwCookie); } } // Force a change notification FontChange(DISPID_UNKNOWN); return hr; } void COleFont::FontChange ( DISPID DispId ) { CY size; BOOL boolVal; short weight; BSTR bstrName; // if not bold font, force clone of normal font if (m_pIFontBold == NULL) { DispId = DISPID_UNKNOWN; } // Copy changed parameter to bold font switch (DispId) { case DISPID_FONT_NAME: if (SUCCEEDED(m_pIFont->get_Name(&bstrName))) { m_pIFontBold->put_Name(bstrName); SysFreeString(bstrName); } break; case DISPID_FONT_SIZE: m_pIFont->get_Size(&size); m_pIFontBold->put_Size(size); break; case DISPID_FONT_ITALIC: m_pIFont->get_Italic(&boolVal); m_pIFontBold->put_Italic(boolVal); break; case DISPID_FONT_UNDER: m_pIFont->get_Underline(&boolVal); m_pIFontBold->put_Underline(boolVal); break; case DISPID_FONT_STRIKE: m_pIFont->get_Strikethrough(&boolVal); m_pIFontBold->put_Strikethrough(boolVal); break; case DISPID_FONT_WEIGHT: m_pIFont->get_Weight(&weight); m_pIFontBold->put_Weight(weight); m_pIFontBold->put_Bold(TRUE); break; case DISPID_UNKNOWN: ClearInterface(m_pIFontBold); if (SUCCEEDED(m_pIFont->Clone(&m_pIFontBold))) { m_pIFontBold->put_Bold(TRUE); } } // Notify owner of font change m_pCtrl->FontChanged(); } STDMETHODIMP COleFont::GetFontDisp ( OUT IFontDisp **ppFont ) { HRESULT hr = S_OK; if (ppFont == NULL) { return E_POINTER; } try { *ppFont = NULL; if (m_pIFont == NULL) { hr = E_UNEXPECTED; } else { hr = m_pIFont->QueryInterface(IID_IFontDisp, (void **)ppFont); } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP COleFont::GetHFont ( OUT HFONT *phFont ) { HRESULT hr = E_FAIL; if (phFont == NULL) { return E_POINTER; } try { *phFont = NULL; if (m_pIFont != NULL ) { hr = m_pIFont->get_hFont(phFont); } if (FAILED(hr)) { *phFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP COleFont::GetHFontBold ( OUT HFONT *phFont ) { HRESULT hr = E_FAIL; if (phFont == NULL) { return E_POINTER; } try { *phFont = NULL; if (m_pIFontBold != NULL ) { hr = m_pIFontBold->get_hFont(phFont); } if ( FAILED(hr)) { *phFont = (HFONT)GetStockObject(DEFAULT_GUI_FONT); } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP COleFont::LoadFromStream ( IN LPSTREAM pIStream ) { HRESULT hr; IPersistStream *pIPersist = NULL; FONTDESC fontDesc; WCHAR achFontFaceName[LF_FACESIZE+1]; LPFONT pIFont = NULL; INT iPxlsPerInch; if (m_pIFont == NULL) { return E_UNEXPECTED; } // Calling pIPersist for the existing font seems to miss some // important notification, so create a new font, load properties // from the stream, and replace the current font. InitDefaultFontDesc ( fontDesc, iPxlsPerInch, achFontFaceName ); hr = OleCreateFontIndirect(&fontDesc, IID_IFont, (void**)&pIFont); if (FAILED(hr)) { return hr; } pIFont->SetRatio(iPxlsPerInch, HIMETRIC_PER_INCH); hr = pIFont->QueryInterface(IID_IPersistStream, (void **)&pIPersist); if (SUCCEEDED(hr)) { hr = pIPersist->Load(pIStream); pIPersist->Release(); hr = SetIFont(pIFont); } pIFont->Release(); return hr; } STDMETHODIMP COleFont::SaveToStream ( IN LPSTREAM pIStream, IN BOOL fClearDirty ) { IPersistStream *pIPersist = NULL; HRESULT hr; if (m_pIFont == NULL) { return E_UNEXPECTED; } hr = m_pIFont->QueryInterface(IID_IPersistStream, (void **)&pIPersist); if (SUCCEEDED(hr)) { hr = pIPersist->Save(pIStream, fClearDirty); pIPersist->Release(); } return hr; } HRESULT COleFont::LoadFromPropertyBag ( IPropertyBag* pIPropBag, IErrorLog* pIErrorLog ) { HRESULT hr = S_OK; WCHAR achFontFaceName[LF_FACESIZE+1]; WCHAR achPropBagFaceName[LF_FACESIZE+1]; INT iBufSize = LF_FACESIZE+1; FONTDESC fontDesc; LPFONT pIFont; VARIANT vValue; BOOL bValue; SHORT iValue; CY cySize; INT iPxlsPerInch; if (m_pIFont == NULL) { return E_UNEXPECTED; } InitDefaultFontDesc ( fontDesc, iPxlsPerInch, achFontFaceName ); hr = StringFromPropertyBag ( pIPropBag, pIErrorLog, L"FontName", achPropBagFaceName, iBufSize ); if ( SUCCEEDED( hr ) ) { fontDesc.lpstrName = achPropBagFaceName; } hr = CyFromPropertyBag ( pIPropBag, pIErrorLog, L"FontSize", cySize ); if ( SUCCEEDED( hr ) ){ fontDesc.cySize.int64 = cySize.int64; } hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, L"FontItalic", bValue ); if ( SUCCEEDED( hr ) ){ fontDesc.fItalic = ( 0 == bValue ? 0 : 1 ); } hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, L"FontUnderline", bValue ); if ( SUCCEEDED( hr ) ){ fontDesc.fUnderline = ( 0 == bValue ? 0 : 1 ); } hr = BOOLFromPropertyBag ( pIPropBag, pIErrorLog, L"FontStrikethrough", bValue ); if ( SUCCEEDED( hr ) ){ fontDesc.fStrikethrough = ( 0 == bValue ? 0 : 1 ); } hr = ShortFromPropertyBag ( pIPropBag, pIErrorLog, L"FontWeight", iValue ); if ( SUCCEEDED( hr ) ){ fontDesc.sWeight = iValue; } hr = OleCreateFontIndirect(&fontDesc, IID_IFont, (void**)&pIFont); if (FAILED(hr)) { return hr; } // pIFont->SetRatio(iPxlsPerInch, HIMETRIC_PER_INCH); hr = SetIFont(pIFont); pIFont->Release(); VariantClear ( &vValue ); return hr; } HRESULT COleFont::SaveToPropertyBag ( IPropertyBag* pIPropBag, BOOL /* fClearDirty */, BOOL /* fSaveAllProps */ ) { HRESULT hr = NOERROR; VARIANT vValue; BOOL bValue; CY cySize; SHORT iValue; if (m_pIFont == NULL) { return E_UNEXPECTED; } do { VariantInit( &vValue ); vValue.vt = VT_BSTR; hr = m_pIFont->get_Name( &vValue.bstrVal); if (!SUCCEEDED(hr)) { break; } hr = pIPropBag->Write(L"FontName", &vValue ); VariantClear ( &vValue ); if (!SUCCEEDED(hr)) { break; } hr = m_pIFont->get_Size ( &cySize ); if (!SUCCEEDED(hr)) { break; } hr = CyToPropertyBag ( pIPropBag, L"FontSize", cySize ); if (!SUCCEEDED(hr)) { break; } hr = m_pIFont->get_Italic ( &bValue ); if (!SUCCEEDED(hr)) { break; } hr = BOOLToPropertyBag ( pIPropBag, L"FontItalic", bValue ); if (!SUCCEEDED(hr)) { break; } hr = m_pIFont->get_Underline ( &bValue ); if (!SUCCEEDED(hr)) { break; } hr = BOOLToPropertyBag ( pIPropBag, L"FontUnderline", bValue ); if (!SUCCEEDED(hr)) { break; } hr = m_pIFont->get_Strikethrough ( &bValue ); if (!SUCCEEDED(hr)) { break; } hr = BOOLToPropertyBag ( pIPropBag, L"FontStrikethrough", bValue ); if (!SUCCEEDED(hr)) { break; } hr = m_pIFont->get_Weight ( &iValue ); if (!SUCCEEDED(hr)) { break; } hr = ShortToPropertyBag ( pIPropBag, L"FontWeight", iValue ); } while (0); return hr; } //---------------------------------------------------------------------------- // CImpIPropertyNotifySink Interface Implementation //---------------------------------------------------------------------------- /* * CImpIPropertyNotifySink::CImpIPropertyNotifySink * CImpIPropertyNotifySink::~CImpIPropertyNotifySink * */ CImpIPropertyNotifySink::CImpIPropertyNotifySink ( IN COleFont *pOleFont ) { m_cRef=0; m_pOleFont = pOleFont; } CImpIPropertyNotifySink::~CImpIPropertyNotifySink ( void ) { } /* * CImpIPropertyNotifySink::QueryInterface * CImpIPropertyNotifySink::AddRef * CImpIPropertyNotifySink::Release * * Purpose: * Non-delegating IUnknown members for CImpIPropertyNotifySink. */ STDMETHODIMP CImpIPropertyNotifySink::QueryInterface ( IN REFIID riid, OUT LPVOID *ppv ) { HRESULT hr = S_OK; if (ppv == NULL) { return E_POINTER; } try { *ppv=NULL; if (IID_IUnknown==riid || IID_IPropertyNotifySink==riid) { *ppv = (LPVOID)this; AddRef(); } else { hr = E_NOINTERFACE; } } catch (...) { hr = E_POINTER; } return hr; } STDMETHODIMP_(ULONG) CImpIPropertyNotifySink::AddRef( void ) { return ++m_cRef; } STDMETHODIMP_(ULONG) CImpIPropertyNotifySink::Release ( void ) { if (0 != --m_cRef) return m_cRef; // delete this; return 0; } STDMETHODIMP CImpIPropertyNotifySink::OnChanged ( IN DISPID DispId ) { // Notify font object of change m_pOleFont->FontChange(DispId); return S_OK; } STDMETHODIMP CImpIPropertyNotifySink::OnRequestEdit ( IN DISPID // DispId ) { return S_OK; }