// FontInfo.cpp : Implementation of CFontInfo #include "stdafx.h" #include "TtfInfo.h" #include "FontInfo.h" ///////////////////////////////////////////////////////////////////////////// // CFontInfo LPCTSTR CFontInfo::m_strFontsKey = NULL; STDMETHODIMP CFontInfo::InterfaceSupportsErrorInfo(REFIID riid) { static const IID* arr[] = { &IID_ITrueTypeFontInfo, }; for ( int i = 0; i < sizeof( arr ) / sizeof( arr[0] ); i++ ) { if ( InlineIsEqualGUID( *arr[i], riid ) ) return S_OK; } return S_FALSE; } STDMETHODIMP CFontInfo::get__FileName(BSTR * pVal) { *pVal = m_bstrFileName.copy(); return S_OK; } STDMETHODIMP CFontInfo::put__FileName(BSTR newVal) { using namespace std; Initialize(); try { m_bstrFileName = _bstr_t(newVal).copy(); } catch (_com_error Err) { m_bstrFileName = ""; return Err.Error(); } const int BUFFER_SIZE = 512; const int MAX_TABLES = 40; wchar_t namebuf[BUFFER_SIZE]; unsigned short numNames; unsigned int cTables; sfnt_OffsetTable OffsetTable; sfnt_DirectoryEntry Table; sfnt_NamingTable NamingTable; sfnt_NameRecord NameRecord; streampos curseek; try { USES_CONVERSION; ifstream TtfFile( W2CA( newVal ), ios_base::in | ios_base::binary ); if ( !TtfFile.is_open() ) { m_bstrFileName = ""; return AtlReportError( CLSID_FontInfo, IDERR_FileOpen, GUID_NULL, E_FAIL, _Module.GetResourceInstance() ); } TtfFile.read( reinterpret_cast( &OffsetTable ), sizeof( OffsetTable ) - sizeof( sfnt_DirectoryEntry ) ); cTables = (int) SWAPW( OffsetTable.numOffsets ); for (int i = 0; i < cTables and i < MAX_TABLES; i++) { TtfFile.read( reinterpret_cast( &Table ), sizeof( Table ) ); if (Table.tag == tag_NamingTable) { TtfFile.seekg( SWAPL( Table.offset ) ); TtfFile.read( reinterpret_cast( &NamingTable ), sizeof( NamingTable ) ); numNames = SWAPW( NamingTable.count ); while ( numNames-- ) { TtfFile.read ( reinterpret_cast( &NameRecord ), sizeof( NameRecord ) ); curseek = TtfFile.tellg(); if ( SWAPW( NameRecord.platformID ) == TTF::Microsoft ) { TtfFile.seekg( SWAPW( NameRecord.offset ) + SWAPW( NamingTable.stringOffset ) + SWAPL( Table.offset ) ); TtfFile.read( reinterpret_cast( &namebuf ), min(SWAPW(NameRecord.length), BUFFER_SIZE) ); namebuf[SWAPW( NameRecord.length ) / sizeof( wchar_t ) ] = L'\0'; for (int i = 0; i < BUFFER_SIZE and i < SWAPW( NameRecord.length ) / sizeof( wchar_t ); i++) namebuf[i] = SWAPW( namebuf[i] ); TtfFile.seekg( curseek ); switch ( SWAPW( NameRecord.nameID ) ) { case TTF::Copyright: m_bstrCopyright = namebuf; break; case TTF::Family: m_bstrFamily = namebuf; break; case TTF::ID: m_bstrID = namebuf; break; case TTF::Name: m_bstrName = namebuf; break; case TTF::PostscriptName: m_bstrPostscriptName = namebuf; break; case TTF::Subfamily: m_bstrSubfamily = namebuf; break; case TTF::Trademark: m_bstrTrademark = namebuf; break; case TTF::Version: m_bstrVersion = namebuf; break; default: break; } } // if ( SWAPW( NameRecord.platformID ) == TTF::Microsoft } // while ( numNames-- ) } // if (Table.tag == tag_NamingTable) } // for (int i = 0; i < cTables and i < 40; i++) } catch(...) { return E_UNEXPECTED; } return S_OK; } STDMETHODIMP CFontInfo::get_FileName(BSTR * pVal) { return get__FileName(pVal); } STDMETHODIMP CFontInfo::put_FileName(BSTR newVal) { return put__FileName(newVal); } STDMETHODIMP CFontInfo::get_Copyright(BSTR * pVal) { *pVal = m_bstrCopyright.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_Family(BSTR * pVal) { *pVal = m_bstrFamily.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_ID(BSTR * pVal) { *pVal = m_bstrID.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_Name(BSTR * pVal) { *pVal = m_bstrName.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_PostscriptName(BSTR * pVal) { *pVal = m_bstrPostscriptName.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_Subfamily(BSTR * pVal) { *pVal = m_bstrSubfamily.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_Trademark(BSTR * pVal) { *pVal = m_bstrTrademark.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_Version(BSTR * pVal) { *pVal = m_bstrVersion.copy(); return S_OK; } STDMETHODIMP CFontInfo::get_RegisteredFileName(BSTR * pVal) { CRegKey reg; LONG lRet = 0; lRet = OpenFontsKey( reg, KEY_READ ); // We'll only return an error in the event that we can't open // the Fonts key, any other registry errors will result in an // empty RegisteredFileName string if ( ERROR_SUCCESS != lRet ) return HRESULT_FROM_WIN32( lRet ); // First get the size DWORD dwSize = 0; lRet = reg.QueryValue( NULL, GetRegistryFontName(), &dwSize ); if ( 0 == dwSize ) { *pVal = _bstr_t("").copy(); return S_OK; } LPTSTR strFileName = new TCHAR [dwSize]; lRet = reg.QueryValue( strFileName, GetRegistryFontName(), &dwSize ); if ( ERROR_SUCCESS != lRet) *pVal = _bstr_t("").copy(); else *pVal = _bstr_t(strFileName).copy(); delete [] strFileName; return S_OK; } STDMETHODIMP CFontInfo::GetFontsDirectory(BSTR * pVal) { LPITEMIDLIST pIDL = NULL; HRESULT hRes = SHGetSpecialFolderLocation( NULL, CSIDL_FONTS, &pIDL ); if ( SUCCEEDED( hRes ) ) { TCHAR pszPath [MAX_PATH] = {0}; BOOL bSuccess = SHGetPathFromIDList( pIDL, pszPath ); CoTaskMemFree( pIDL ); if ( bSuccess ) { *pVal = _bstr_t( pszPath ).copy(); return S_OK; } else hRes = E_FAIL; } return AtlReportError( CLSID_FontInfo, IDERR_GetFontsDirectory, GUID_NULL, hRes, _Module.GetResourceInstance() ); } STDMETHODIMP CFontInfo::Install(VARIANT_BOOL bPermanent) { if ( _bstr_t("") == m_bstrFileName ) return AtlReportError( CLSID_FontInfo, IDERR_NoFileName, GUID_NULL, E_FAIL, _Module.GetResourceInstance() ); if ( VARIANT_TRUE == bPermanent ) { // It's up to the user to check whether this font is already installed CRegKey reg; LONG lRet = 0; lRet = OpenFontsKey( reg, KEY_WRITE ); if ( ERROR_SUCCESS != lRet ) return AtlReportError( CLSID_FontInfo, IDERR_OpenFontsKey, GUID_NULL, HRESULT_FROM_WIN32( lRet ), _Module.GetResourceInstance() ); lRet = reg.SetValue( m_bstrFileName, GetRegistryFontName() ); if ( ERROR_SUCCESS != lRet ) return AtlReportError( CLSID_FontInfo, IDERR_Install, GUID_NULL, HRESULT_FROM_WIN32( lRet ), _Module.GetResourceInstance() ); } int ret = AddFontResource( m_bstrFileName ); ::SendMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, 0 ); return S_OK; } STDMETHODIMP CFontInfo::Uninstall(VARIANT_BOOL bPermanent) { if ( _bstr_t("") == m_bstrFileName ) return AtlReportError( CLSID_FontInfo, IDERR_NoFileName, GUID_NULL, E_FAIL, _Module.GetResourceInstance() ); if ( VARIANT_TRUE == bPermanent ) { // It's up to the user to ensure that they really // want to remove the font before calling this method CRegKey reg; LONG lRet = 0; lRet = OpenFontsKey(reg, KEY_WRITE ); if ( ERROR_SUCCESS != lRet ) return AtlReportError( CLSID_FontInfo, IDERR_OpenFontsKey, GUID_NULL, HRESULT_FROM_WIN32( lRet ), _Module.GetResourceInstance() ); lRet = reg.DeleteValue( GetRegistryFontName() ); if ( ERROR_SUCCESS != lRet ) return AtlReportError( CLSID_FontInfo, IDERR_Uninstall, GUID_NULL, HRESULT_FROM_WIN32( lRet ), _Module.GetResourceInstance() ); } int ret = RemoveFontResource( m_bstrFileName ); ::SendMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, 0 ); return S_OK; }