win10部分字体不能安装-(Win10无法安装字体)

来源:191路由网 2022-11-26 13:25:40

win10部分字体不能安装 (Win10无法安装字体)

#程序员##IT教育##软件开发##软件工程师##cpp#

锐英源精品原创,禁止全文或局部转载,禁止任何形式的非法使用,侵权必究。点名“简易百科”和闲暇巴盗用锐英源原创内容。


背景

显示文本是软件常用功能,而显示文本依赖字体,字体的安装卸载有时候很麻烦,内嵌字体资源比较保险。翻译本文,供大家参考学习。

介绍

每隔一段时间,我们开发的应用程序就需要用户系统中可能存在也可能不存在的字体。一个常见的解决方案是将字体文件与应用程序设置的其余部分捆绑在一起,并将它们与其他所有内容一起安装。诸如 MSI、NSIS 或 Inno 之类的软件包使这很容易。一个缺点是您的字体在系统范围内永久可见,例如,用户可以随时删除/卸载您的应用程序所依赖的字体。为了防止这种情况,您可以实现代码,在每次运行应用程序时检查字体的状态,如果需要,继续自行终止、警告用户或即时安装字体。

当然,如果您正在动态安装字体,您可以更进一步,将字体的生命周期限制为应用程序的执行。该方法将具有额外的优势,即在一定程度上保护字体的“隐私”,因为它仅在您的应用程序启动时可见。本文介绍了一个简单的类,它封装了这样的功能,即允许应用程序从编译的资源中动态安装/卸载字体,只需几行代码。

使用代码

代码的直接使用将遵循以下步骤:

在项目中包含AP_FontInstaller.hAP_FontInstaller.cpp。将相关字体文件作为资源添加到项目中。将CAP_FontInstaller类标题插入到主对话框的标题中:#include " AP_FontInstaller.h"创建类的对象CAP_FontInstaller:CAP_FontInstaller m_capFontInstaller;在 中OnInitDialog(),将字体资源添加到安装程序并安装字体:m_capFontInstaller .AddFont( _T("Camelot MF"), IDR_FONT_CAMELOT, _T("FONTS") ) .AddFont( _T("Cigno MF"), IDR_FONT_CIGNO, _T("FONTS") ); m_capFontInstaller.InstallAllFonts();确保在应用程序终止之前卸载字体,例如,在OnClose()方法中:m_capFontInstaller.UninstallAllFonts();

只有系统中不存在的字体才会被CAP_FontInstaller类安装和卸载。因此,如果您忘记卸载字体,下次运行应用程序时,它会将这些字体标记为已存在,您将无法卸载它们。当然,您也可以修改代码的行为以适应其他用途,这可能不是问题。

兴趣点

该类的代码CAP_FontInstaller旨在实现一个相当简单的公式,即保留一个可以安装和卸载的字体列表。要尊重的规则是,如果系统中已经存在任何这些字体,它们将不会被干预。

因此,首要任务是找出已经安装了哪些字体。这是通过调用 API 来完成的,而 APIEnumFontFamiliesEx又依赖于回调函数的实现。代码如下所示:

BOOL CAP_FontInstaller::IsFontAlreadyInSystem( const CString& csFontName ){ HDC hDC = GetDC( NULL ); LOGFONT lf = { 0, 0, 0, 0, 0, 0, 0, 0, ANSI_CHARSET, 0, 0, 0, 0, NULL }; FONT_DETAILS fdFont; fdFont.m_csFontName = csFontName; fdFont.m_bInstalled = FALSE; EnumFontFamiliesEx( hDC, &lf, (FONTENUMPROC)_EnumFontFamExProc, (LPARAM)(LPVOID)&fdFont, 0 ); return fdFont.m_bInstalled;}int CALLBACK CAP_FontInstaller::_EnumFontFamExProc( ENUMLOGFONTEX * lpelfe, NEWTEXTMETRICEX * /*lpntme*/, int /*nFontType*/, LPARAM lParam ){ PFONT_DETAILS pfd = (PFONT_DETAILS)lParam; if( pfd->m_csFontName == lpelfe->elfLogFont.lfFaceName ) { pfd->m_bInstalled = TRUE; return FALSE; // Finished } else return TRUE; // Continue}

回调函数_EnumFontFamExProc由系统调用,一次只针对一种字体。请注意,face-name 不必(而且通常不是)与字体文件名相同。如有疑问,请使用字体查看器。

注:这个不相同,意义很大。

如前所述,安装程序会保留要安装/卸载的字体列表。此列表是一个结构数组,其声明如下所示:

typedef struct{ CString m_csFontName; CString m_csInstalledFontFullPath; UINT m_uResID; CString m_csResType; BOOL m_bInstalled; BOOL m_bAlreadyInTheSystem;} FONT_DETAILS, *PFONT_DETAILS;

对于传递给公共方法的每种字体,都会填充一个结构并将其添加到数组中AddFont。

安装涉及从应用程序的编译资源中提取字体并在相应的系统文件夹中创建字体文件(视操作系统版本而异)。代码如下所示:

BOOL CAP_FontInstaller::WriteFontFile( const CString& csInstalledFontFullPath, UINT uResID, const CString& csResType ){ BOOL bSuccess = FALSE; HINSTANCE hInst = AfxGetResourceHandle(); HRSRC hResource = FindResource( hInst, MAKEINTRESOURCE( uResID ), csResType ); if( hResource ) { HGLOBAL hGlobal = LoadResource( hInst, hResource ); if( hGlobal ) { TCHAR* szTemp = (TCHAR*)LockResource( hGlobal ); UINT uSize = (UINT)SizeofResource( hInst, hResource ); DeleteObject( (HGDIOBJ)hGlobal ); CFile cf; if( cf.Open( csInstalledFontFullPath, CFile::modeWrite | CFile::modeCreate ) ) { cf.Write( szTemp, uSize ); cf.Close(); bSuccess = TRUE; } } } return bSuccess;}BOOL CAP_FontInstaller::InstallFont( const CString& csFontName ){ BOOL bSuccess = FALSE; PFONT_DETAILS pfd = NULL; if( FindFontDescription( csFontName, pfd ) && pfd->m_bInstalled == FALSE && pfd->m_bAlreadyInTheSystem == FALSE && WriteFontFile( pfd->m_csInstalledFontFullPath, pfd->m_uResID, pfd->m_csResType ) ) { bSuccess = ( AddFontResource( pfd->m_csInstalledFontFullPath ) != 0 ); pfd->m_bInstalled = bSuccess; } return bSuccess;}

如您所见,提取资源和编写字体文件很简单。如果成功,安装字体需要调用 API AddFontResource。

卸载更简单:首先调用 API RemoveFontResource,然后删除字体文件本身。

BOOL CAP_FontInstaller::UninstallFont( const CString& csFontName ){ BOOL bSuccess = FALSE; PFONT_DETAILS pfd = NULL; if( FindFontDescription( csFontName, pfd ) && pfd->m_bInstalled == TRUE && pfd->m_bAlreadyInTheSystem == FALSE && RemoveFontResource( pfd->m_csInstalledFontFullPath ) ) { _unlink( pfd->m_csInstalledFontFullPath ); pfd->m_bInstalled = FALSE; bSuccess = TRUE; } return bSuccess;}

请记住,如果字体文件被系统锁定,调用_unlink将失败。

笔记

Windows 在修改字体方面特别挑剔。因此,让我提醒您,代码按“原样”提供,没有任何明示或暗示的保证。继续需要您自担风险。

用于演示项目的字体(Camelot MF 和 Cigno MF)是 Rick W. Mueller 的财产。

演示应用程序/项目不是很复杂。如果任一字体已安装在您的系统中,则演示将无法安装/卸载字体,因此将无法正常工作。


路由
点击展开全文

相关阅读

电脑usb接口关闭怎么打开-(电脑usb接口关闭怎么打开)

电脑usb接口关闭怎么打开(电脑usb接口关闭怎么打开)1.电脑机箱的正面USB端口不可用许多人的计算机无法使用主机的前置USB接口。主机的正面USB接口通过数据线连接到主板的相应端口。如果连接松动或中间数据线出现问题,则主机的正面USB接口将无法使用。主机背面的USB接口在主板上...

2022-11-26

u盘为什么读不怎么办-(u盘不读怎么回事)

u盘为什么读不怎么办(u盘不读怎么回事)U盘无法读取?出现这种状况的原因太多了。但有一种状况是经常发生的,那就是U盘在自己的电脑里读不出来,但在桌面右下角又有U盘的图标,而在电脑里却怎么也找不着,这是怎么回事呢?如果你将U盘插入到其他电脑里,它又能读取出来。针对这种状况,咱们一起来学习一下吧!第一步:在桌面上...

2022-11-26

神舟bios设置图解教程-(神舟bios设置图解教程z7)

神舟bios设置图解教程(神舟bios设置图解教程z7)教程开始,首先是刷BIOS教程教程之前这里需要提三点第一点:刷BIOS并不是万能的,在神舟战神出现风扇抽风或者无法解决的驱动问题的时候建议刷BIOS。第二点:BIOS毕竟是底层的东西,很多人表示有压力怕刷坏,其实按照步...

2022-11-26

win10怎样关闭defender-(Win10怎样关闭防火墙)

win10怎样关闭defender(Win10怎样关闭防火墙)在给电脑重装系统的时候,有的朋友可能会提示关闭安全软件和防火墙才能继续操作,很多朋友都在电脑上关闭了安全软件还是重装不了系统,可能是因为没有正确关闭防火墙,那么win10电脑防火墙怎么关闭呢?电脑:华硕p40系统:win10专业版1、在电脑桌面...

2022-11-26

win7纯净版u盘启动盘制作-(win7 u盘启动盘制作)

win7纯净版u盘启动盘制作(win7u盘启动盘制作)经常有朋友问小编如何制作纯净版win7启动u盘,因为大家都很想要学会这个方法,只要学会了这个方法,我们以后就可以无所顾忌的重装电脑系统啦u启动u盘启动盘制作工具:1、更新软件界面...

2022-11-26

191路由网 - 192.168.1.1,192.168.0.1无线路由器设置教程

版权声明:本站的文章和图片来自互联网收集,仅做分享之用如有侵权请联系站长,我们将在24小时内删除