dotnet 读 WPF 源代码笔记 了解 WPF 已知问题 用户设备上不存在 Arial 字体将导致应用闪退
本文来告诉大家 WPF 已知问题,在用户的设备上,如果不存在 Arial 字体,同时安装了一些诡异的字体,那么也许就会让应用在使用到诡异的字体的时候,软件闪退
在 WPF 的 FontFamily.cs 字体类里面,有一个叫 FirstFontFamily 的属性,这个属性的逻辑代码里面将包括在当前字体太过诡异时,自动 Fallback 到默认的字体,而默认的字体就是 Arial 字体。这个属性将会在很多逻辑被调用,如获取 FamilyNames 时
public LanguageSpecificStringDictionary FamilyNames
{
get
{
CompositeFontFamily compositeFont = FirstFontFamily as CompositeFontFamily;
if (compositeFont != null)
{
// Return the read/write dictionary of family names.
return compositeFont.FamilyNames;
}
else
{
// Return a wrapper for the cached family's read-only dictionary.
return new LanguageSpecificStringDictionary(FirstFontFamily.Names);
}
}
}
在进入到寻找 Fallback 字体将会进入到 Invariant 的 Assert 判断方法,在这里面找不到 Arial 字体时,将会进入 Environment.FailFast 让应用程序闪退
以下是 FirstFontFamily 属性的代码,代码我删除了不关键部分
if (family == null)
{
FontStyle style = FontStyles.Normal;
FontWeight weight = FontWeights.Normal;
FontStretch stretch = FontStretches.Normal;
family = FindFirstFontFamilyAndFace(ref style, ref weight, ref stretch);
if (family == null)
{
// 进入这里的逻辑将会去寻找 Fallback 字体
// fall back to null font
family = LookupFontFamily(NullFontFamilyCanonicalName);
Invariant.Assert(family != null);
}
在 LookupFontFamily 函数里面,将会尝试去寻找 Arial 字体,上面代码的 NullFontFamilyCanonicalName 默认就是使用 Arial 字体
internal static readonly CanonicalFontFamilyReference NullFontFamilyCanonicalName = CanonicalFontFamilyReference.Create(null, "#ARIAL");
在 LookupFontFamily 函数里面将会调用 LookupFontFamilyAndFace 函数去寻找传入的字体,寻找的方法是从 _defaultFamilyCollection
去寻找传入的字体
这里的 _defaultFamilyCollection
是在静态构造时获取的,代码如下
private static volatile FamilyCollection _defaultFamilyCollection = PreCreateDefaultFamilyCollection();
以上的 PreCreateDefaultFamilyCollection 函数,实际就是读取 WindowsFontsUriObject 列表,这里的 Windows 指的不是窗口,而是指 Windows 系统
private static FamilyCollection PreCreateDefaultFamilyCollection()
{
FamilyCollection familyCollection = FamilyCollection.FromWindowsFonts(Util.WindowsFontsUriObject);
return familyCollection;
}
以上的 WindowsFontsUriObject 定义如下
private const string WinDir = "windir";
string s = Environment.GetEnvironmentVariable(WinDir) + @"\Fonts\";
_windowsFontsLocalPath = s.ToUpperInvariant();
_windowsFontsUriObject = new Uri(_windowsFontsLocalPath, UriKind.Absolute);
也就是说读取的就是 windir 文件夹下的 Fonts 文件夹,也就是 C:\Windows\Fonts\
文件夹
在 LookupFontFamilyAndFace 将会尝试去从 C:\Windows\Fonts\
文件夹寻找字体
IFontFamily fontFamily = familyCollection.LookupFamily
(
canonicalFamilyReference.FamilyName,
ref style,
ref weight,
ref stretch
);
假定用户从 C:\Windows\Fonts\
文件夹删除了 Arial 字体,那么将找不到字体,返回是空
也就是 LookupFontFamily 将返回空
internal static IFontFamily LookupFontFamily(CanonicalFontFamilyReference canonicalName)
{
FontStyle style = FontStyles.Normal;
FontWeight weight = FontWeights.Normal;
FontStretch stretch = FontStretches.Normal;
return LookupFontFamilyAndFace(canonicalName, ref style, ref weight, ref stretch);
}
在 FirstFontFamily 属性里面,判断字体存在的代码如下
family = LookupFontFamily(NullFontFamilyCanonicalName);
Invariant.Assert(family != null);
在用户删除了 Arial 字体,将会让 family 是空,而在 Invariant 的定义代码如下
internal static void Assert(bool condition)
{
if (!condition)
{
FailFast(null, null);
}
}
以上的 FailFast 方法将会调用 Environment.FailFast 方法
private // DO NOT MAKE PUBLIC OR INTERNAL -- See security note
static void FailFast(string message, string detailMessage)
{
if (Invariant.IsDialogOverrideEnabled)
{
// This is the override for stress and other automation.
// Automated systems can't handle a popup-dialog, so let
// them jump straight into the debugger.
Debugger.Break();
}
Debug.Assert(false, "Invariant failure: " + message, detailMessage);
Environment.FailFast(SR.Get(SRID.InvariantFailure));
}
调用 Environment.FailFast 之后,应用程序就闪退了,只有在系统事件里面看到记录
我认为这是一个不合理的设计,至少在框架层不应该有这样的逻辑,作为一个十分成熟的 UI 框架,应该能兼容各个诡异的系统,我将这个问题报告给官方,请看 WPF known issues: Application will FailFast when not find the Arial font from system · Issue #4464 · dotnet/wpf
dotnet 读 WPF 源代码笔记 了解 WPF 已知问题 用户设备上不存在 Arial 字体将导致应用闪退的更多相关文章
- dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标
大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...
- dotnet 读 WPF 源代码笔记 渲染收集是如何触发
在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...
- 已知root用户密码并登录,修改mysql用户名密码方法
首先进入命令行下:以root用户登录,命令:mysql -uroot -p 回车 输入密码:mysql>use mysql:mysql>UPDATE user SET password=P ...
- Android笔记--报错AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY in "create table if not exists user_info(导致APP闪退)
问题描述 每次一运行,APP程序必定闪退,百度了发现,闪退问题绝大多数就跟sql语句有关: 看到控制台报出这样的错误: 百度发现,我忘记了最初的知识点: 在表里面,自动递增是在数据类型为Integer ...
- 《深入浅出WPF》笔记——资源篇
原文:<深入浅出WPF>笔记--资源篇 前面的记录有的地方已经用到了资源,本文就来详细的记录一下WPF中的资源.我们平时的“资源”一词是指“资财之源”,是创造人类社会财富的源泉.在计算机程 ...
- WPF自学笔记
WPF使用哪几种元素作为顶级元素: 1. Window元素 2. Page元素(与Window元素类似,用于可导航的应用程序) 3. Application元素(定义应用程序资源和启动设置) PS:在 ...
- 《深入浅出WPF》笔记——绘画与动画
<深入浅出WPF>笔记——绘画与动画 本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...
- 《深入浅出WPF》笔记——模板篇
原文:<深入浅出WPF>笔记--模板篇 我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照. 一.认识模板 1.1WPF菜鸟看模板 前面的记录有提过,控件主要是算法 ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...
- 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]
原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果) 浮雕效果主要有两个参数:Amount和Wid ...
随机推荐
- 记录--Cesium+Vue实战教程——地图导航
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 项目效果 我们今天要实现的是一个路径规划的功能,有两个输入框.输入起点终点,然后查询,得到规划的路径,效果如下: 我们会用到以下库: Ax ...
- C#的播放资源文件里的音频例子 - 开源研究系列文章
今天无聊,想起原来开发的待办列表TodoList里还缺个提醒声音,于是就添加了提供声音模块代码.然后想着记录一下,让更多的读者能够复用这个模块代码,于是就有了此博文.这个例子只是用于播放资源文件里的w ...
- 《.NET内存管理宝典 》(Pro .NET Memory Management) 阅读指南 - 第10章
本章勘误: 暂无,等待细心的你告诉我哦. 本章注解: 暂无 本章释疑: 暂无,等待你的提问 致谢: MVP 林德熙 MVP 吕毅 sPhinX 相关链接 试读记录
- 基于logisim-D触发器设计四人抢答电路
实验1:设计一个简易4人知识竞赛抢答电路,要求是: 裁判掌握一个按钮,作用是给电路复位和发出抢答开始命令;4名竞赛者各掌握一个按钮,每人对应一个指示灯,在主持人发出开始抢答命令后,哪位参赛者先按钮其对 ...
- 表名大小写混合时格式问题及sys_dump导出时的注意事项
前言 前几天碰到同事咨询一个有关sys_dump导出时,表名为大小写混合情况的报错问题.因为sys_dump命令运行在linux操作系统上,所以这涉及到linux中shell的语法格式问题. 下面模拟 ...
- 终于来了!FastGPT 正式兼容 GPT 应用
终于来了!FastGPT 正式兼容 GPT 应用 FastGPT V4.7 正式加入了工具调用功能,可以兼容 GPTs 的 Actions.这意味着,你可以直接导入兼容 GPTs 的 Agent 工具 ...
- 腾讯tvp之路
王清培 腾讯tvp之路
- Scala 可变列表ListBuffer
1 package chapter07 2 3 import scala.collection.mutable.ListBuffer 4 5 object Test05_ListBuffer { 6 ...
- C++设计模式 - 享元模式(Flyweight)
对象性能模式 面向对象很好地解决了"抽象"的问题,但是必不可免地要付出一定的代价.对于通常情况来讲,面向对象的成本大都可以忽略不计.但是某些情况,面向对象所带来的成本必须谨慎处理. ...
- 5W1H聊开源之Who/When/Where——谁在何时何地“发明”了开源?
美国政治传播学家拉斯韦尔提出了5W传播模式,经过后人的不断运用和发展总结,形成了一套逐渐成熟的"5W1H"体系,即:对选定的项目.工序或操作,都要从原因(何因Why).对象(何事W ...