本文来告诉大家 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 字体将导致应用闪退的更多相关文章

  1. dotnet 读 WPF 源代码笔记 布局时 Arrange 如何影响元素渲染坐标

    大家是否好奇,在 WPF 里面,对 UIElement 重写 OnRender 方法进行渲染的内容,是如何受到上层容器控件的布局而进行坐标偏移.如有两个放入到 StackPanel 的自定义 UIEl ...

  2. dotnet 读 WPF 源代码笔记 渲染收集是如何触发

    在 WPF 里面,渲染可以从架构上划分为两层.上层是 WPF 框架的 OnRender 之类的函数,作用是收集应用程序渲染的命令.上层将收集到的应用程序绘制渲染的命令传给下层,下层是 WPF 的 GF ...

  3. 已知root用户密码并登录,修改mysql用户名密码方法

    首先进入命令行下:以root用户登录,命令:mysql -uroot -p 回车 输入密码:mysql>use mysql:mysql>UPDATE user SET password=P ...

  4. Android笔记--报错AUTOINCREMENT is only allowed on an INTEGER PRIMARY KEY in "create table if not exists user_info(导致APP闪退)

    问题描述 每次一运行,APP程序必定闪退,百度了发现,闪退问题绝大多数就跟sql语句有关: 看到控制台报出这样的错误: 百度发现,我忘记了最初的知识点: 在表里面,自动递增是在数据类型为Integer ...

  5. 《深入浅出WPF》笔记——资源篇

    原文:<深入浅出WPF>笔记--资源篇 前面的记录有的地方已经用到了资源,本文就来详细的记录一下WPF中的资源.我们平时的“资源”一词是指“资财之源”,是创造人类社会财富的源泉.在计算机程 ...

  6. WPF自学笔记

    WPF使用哪几种元素作为顶级元素: 1. Window元素 2. Page元素(与Window元素类似,用于可导航的应用程序) 3. Application元素(定义应用程序资源和启动设置) PS:在 ...

  7. 《深入浅出WPF》笔记——绘画与动画

    <深入浅出WPF>笔记——绘画与动画   本篇将记录一下如何在WPF中绘画和设计动画,这方面一直都不是VS的强项,然而它有一套利器Blend:这方面也不是我的优势,幸好我有博客园,能记录一 ...

  8. 《深入浅出WPF》笔记——模板篇

    原文:<深入浅出WPF>笔记--模板篇 我们通常说的模板是用来参照的,同样在WPF中,模板是用来作为制作控件的参照. 一.认识模板 1.1WPF菜鸟看模板 前面的记录有提过,控件主要是算法 ...

  9. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[DirectionalBlur]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[DirectionalBlur] 方位模糊是一个按照指定角度循环位移并叠加纹理,最后平均颜色值并输出的一种特效. ...

  10. 【HLSL学习笔记】WPF Shader Effect Library算法解读之[Embossed]

    原文:[HLSL学习笔记]WPF Shader Effect Library算法解读之[Embossed] Embossed(浮雕效果)          浮雕效果主要有两个参数:Amount和Wid ...

随机推荐

  1. 《Go程序设计语言》学习笔记之函数变量和匿名函数

    <Go程序设计语言>学习笔记之函数变量和匿名函数 一. 环境 Centos8.5, go1.17.5 linux/amd64 二. 函数变量 1. 概念 像其它的值一样,函数变量也有类型, ...

  2. nohup操作

    nohup操作 背景:vscode 连接服务器远程运行时经常会出现断连需要重新输入密码,如果是在终端跑程序那么中断后无法再恢复在终端的输出,为了能够让程序保留实验结果或需要长时间跑程序而无需值守,需要 ...

  3. 没有Python基础,如何学习用Python写机器学习

    前言 我是一个完全没用过python的人,所以,想写机器学习,就得从语法入手. 首先上W3cSchool去学习基础语法. 基础语法都差不多,重点看一下函数,模块,面向对象. 函数的写法稍有不同,格式上 ...

  4. Tarjan 算法——图论学习笔记

    Part.1 引入 在图论问题中,我们经常去研究一些连通性问题,比如: 有向图的联通性:传递闭包--Floyd 算法: 有向图连通性的对称性:强联通分量(SCC)--Tarjan 算法缩点: 无向图的 ...

  5. 20 JavaScript和HTML交互

    20 JavaScript和HTML交互 在HTML中可以直接在标签上给出一些事件的触发. 例如, 页面上的一个按钮. <input type="button" value= ...

  6. #dp#NOIP2020.9.26模拟jerry

    题目 Jerry 写下了一个只由非负整数和加减号组成的算式. 它想给这个算式添加合法的括号,使得算式的结果最大. 分析 考场\(O(n^3)\)伪部分分成功爆零, 设\(dp[i][j]\)表示前\( ...

  7. #深搜,期望#CF105B Dark Assembly

    洛谷题目传送门 CODEFORCES传送门 分析 题目强调贿赂要在投票开始前完成说明分糖和成功率可以分开计算 那么分糖考虑直接暴搜,由于题目并没有说糖必须全部分完, 所以每一次分完一颗糖后均要求当前状 ...

  8. OpenHarmony创新赛丨报名倒计时,超强秘籍带你直通大奖!

      OpenHarmony创新赛报名倒计时开始啦! 设于开放原子全球开源大赛下的OpenHarmony创新赛,目前正在如火如荼地进行赛事招募中!这次大赛围绕创新应用.商显行业.金融行业三大赛题,邀请来 ...

  9. 资讯速递 | ArkUI-X 预览版已正式开源!

     OpenHarmony项目群技术指导委员会(以下简称"TSC")-跨平台应用开发框架TSG所孵化项目 -- ArkUI-X,近期已正式开源 ,开发者基于一套主代码,就可以将在Op ...

  10. Seaborn线性关系数据可视化

    regplot() 绘制两个变量的线性拟合图. sns.regplot( x, y, data=None, x_estimator=None, x_bins=None, x_ci='ci', scat ...