├── .editorconfig
├── .gitignore
├── FontLink Settings.sln
├── FontLink Settings
├── App.config
├── App.xaml
├── App.xaml.cs
├── FallbackTemplateSelector.cs
├── FodyWeavers.xml
├── FodyWeavers.xsd
├── FontLink Settings.csproj
├── FontLinkFallback.cs
├── MainWindow.xaml
├── MainWindow.xaml.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── Resources.Designer.cs
│ ├── Resources.resx
│ ├── Settings.Designer.cs
│ └── Settings.settings
├── Resources
│ └── App.ico
└── Utilities
│ └── SecurityHelpers.cs
├── License.txt
└── ReadMe.md
/.editorconfig:
--------------------------------------------------------------------------------
1 | # Remove the line below if you want to inherit .editorconfig settings from higher directories
2 | root = true
3 |
4 | # C# files
5 | [*.cs]
6 |
7 | #### Core EditorConfig Options ####
8 |
9 | # Indentation and spacing
10 | indent_size = 4
11 | indent_style = space
12 | tab_width = 4
13 |
14 | # New line preferences
15 | end_of_line = crlf
16 | insert_final_newline = true
17 |
18 | #### .NET Coding Conventions ####
19 |
20 | # this. and Me. preferences
21 | dotnet_style_qualification_for_event = false:silent
22 | dotnet_style_qualification_for_field = false:silent
23 | dotnet_style_qualification_for_method = false:silent
24 | dotnet_style_qualification_for_property = false:silent
25 |
26 | # Language keywords vs BCL types preferences
27 | dotnet_style_predefined_type_for_locals_parameters_members = false:silent
28 | dotnet_style_predefined_type_for_member_access = false:suggestion
29 |
30 | # Parentheses preferences
31 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:suggestion
32 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:suggestion
33 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:suggestion
34 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:suggestion
35 |
36 | # Modifier preferences
37 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent
38 |
39 | # Expression-level preferences
40 | csharp_style_deconstructed_variable_declaration = true:suggestion
41 | csharp_style_inlined_variable_declaration = true:suggestion
42 | csharp_style_throw_expression = true:suggestion
43 | dotnet_style_coalesce_expression = true:suggestion
44 | dotnet_style_collection_initializer = true:suggestion
45 | dotnet_style_explicit_tuple_names = true:suggestion
46 | dotnet_style_null_propagation = true:suggestion
47 | dotnet_style_object_initializer = true:suggestion
48 | dotnet_style_prefer_auto_properties = true:silent
49 | dotnet_style_prefer_compound_assignment = true:suggestion
50 | dotnet_style_prefer_conditional_expression_over_assignment = true:suggestion
51 | dotnet_style_prefer_conditional_expression_over_return = true:suggestion
52 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion
53 | dotnet_style_prefer_inferred_tuple_names = true:suggestion
54 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion
55 |
56 | # Field preferences
57 | dotnet_style_readonly_field = true:suggestion
58 |
59 | # Parameter preferences
60 | dotnet_code_quality_unused_parameters = all:suggestion
61 |
62 | #### C# Coding Conventions ####
63 |
64 | # var preferences
65 | csharp_style_var_elsewhere = true:silent
66 | csharp_style_var_for_built_in_types = true:silent
67 | csharp_style_var_when_type_is_apparent = true:suggestion
68 |
69 | # Expression-bodied members
70 | csharp_style_expression_bodied_accessors = when_on_single_line:silent
71 | csharp_style_expression_bodied_constructors = when_on_single_line:silent
72 | csharp_style_expression_bodied_indexers = when_on_single_line:silent
73 | csharp_style_expression_bodied_lambdas = when_on_single_line:silent
74 | csharp_style_expression_bodied_local_functions = when_on_single_line:silent
75 | csharp_style_expression_bodied_methods = when_on_single_line:silent
76 | csharp_style_expression_bodied_operators = when_on_single_line:silent
77 | csharp_style_expression_bodied_properties = when_on_single_line:silent
78 |
79 | # Pattern matching preferences
80 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
81 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
82 |
83 | # Null-checking preferences
84 | csharp_style_conditional_delegate_call = true:suggestion
85 |
86 | # Modifier preferences
87 | csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async
88 |
89 | # Code-block preferences
90 | csharp_prefer_braces = true:silent
91 |
92 | # Expression-level preferences
93 | csharp_prefer_simple_default_expression = true:suggestion
94 | csharp_style_pattern_local_over_anonymous_function = true:suggestion
95 | csharp_style_prefer_index_operator = true:suggestion
96 | csharp_style_prefer_range_operator = true:suggestion
97 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion
98 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent
99 |
100 | #### C# Formatting Rules ####
101 |
102 | # New line preferences
103 | csharp_new_line_before_catch = true
104 | csharp_new_line_before_else = true
105 | csharp_new_line_before_finally = true
106 | csharp_new_line_before_members_in_anonymous_types = true
107 | csharp_new_line_before_members_in_object_initializers = true
108 | csharp_new_line_before_open_brace = all
109 | csharp_new_line_between_query_expression_clauses = true
110 |
111 | # Indentation preferences
112 | csharp_indent_block_contents = true
113 | csharp_indent_braces = false
114 | csharp_indent_case_contents = true
115 | csharp_indent_case_contents_when_block = false
116 | csharp_indent_labels = one_less_than_current
117 | csharp_indent_switch_labels = false
118 |
119 | # Space preferences
120 | csharp_space_after_cast = true
121 | csharp_space_after_colon_in_inheritance_clause = true
122 | csharp_space_after_comma = true
123 | csharp_space_after_dot = false
124 | csharp_space_after_keywords_in_control_flow_statements = true
125 | csharp_space_after_semicolon_in_for_statement = true
126 | csharp_space_around_binary_operators = before_and_after
127 | csharp_space_around_declaration_statements = false
128 | csharp_space_before_colon_in_inheritance_clause = true
129 | csharp_space_before_comma = false
130 | csharp_space_before_dot = false
131 | csharp_space_before_open_square_brackets = false
132 | csharp_space_before_semicolon_in_for_statement = false
133 | csharp_space_between_empty_square_brackets = false
134 | csharp_space_between_method_call_empty_parameter_list_parentheses = false
135 | csharp_space_between_method_call_name_and_opening_parenthesis = false
136 | csharp_space_between_method_call_parameter_list_parentheses = false
137 | csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
138 | csharp_space_between_method_declaration_name_and_open_parenthesis = false
139 | csharp_space_between_method_declaration_parameter_list_parentheses = false
140 | csharp_space_between_parentheses = false
141 | csharp_space_between_square_brackets = false
142 |
143 | # Wrapping preferences
144 | csharp_preserve_single_line_blocks = true
145 | csharp_preserve_single_line_statements = false
146 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # User-specific files
2 | .vs/
3 | *.suo
4 | *.user
5 | *.sln.docstates
6 |
7 | # Build results
8 | [Dd]ebug/
9 | [Rr]elease/
10 | x64/
11 | build/
12 | [Bb]in/
13 | [Oo]bj/
14 |
15 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
16 | !packages/*/build/
17 |
18 | # MSTest test Results
19 | [Tt]est[Rr]esult*/
20 | [Bb]uild[Ll]og.*
21 |
22 | *_i.c
23 | *_p.c
24 | *.ilk
25 | *.meta
26 | *.obj
27 | *.pch
28 | *.pdb
29 | *.pgc
30 | *.pgd
31 | *.rsp
32 | *.sbr
33 | *.tlb
34 | *.tli
35 | *.tlh
36 | *.tmp
37 | *.tmp_proj
38 | *.log
39 | *.vspscc
40 | *.vssscc
41 | .builds
42 | *.pidb
43 | *.log
44 | *.scc
45 |
46 | # Visual C++ cache files
47 | ipch/
48 | *.aps
49 | *.ncb
50 | *.opensdf
51 | *.sdf
52 | *.cachefile
53 |
54 | # Visual Studio profiler
55 | *.psess
56 | *.vsp
57 | *.vspx
58 |
59 | # Guidance Automation Toolkit
60 | *.gpState
61 |
62 | # ReSharper is a .NET coding add-in
63 | _ReSharper*/
64 | *.[Rr]e[Ss]harper
65 |
66 | # TeamCity is a build add-in
67 | _TeamCity*
68 |
69 | # DotCover is a Code Coverage Tool
70 | *.dotCover
71 |
72 | # NCrunch
73 | *.ncrunch*
74 | .*crunch*.local.xml
75 |
76 | # Installshield output folder
77 | [Ee]xpress/
78 |
79 | # DocProject is a documentation generator add-in
80 | DocProject/buildhelp/
81 | DocProject/Help/*.HxT
82 | DocProject/Help/*.HxC
83 | DocProject/Help/*.hhc
84 | DocProject/Help/*.hhk
85 | DocProject/Help/*.hhp
86 | DocProject/Help/Html2
87 | DocProject/Help/html
88 |
89 | # Click-Once directory
90 | publish/
91 |
92 | # Publish Web Output
93 | *.Publish.xml
94 | *.pubxml
95 |
96 | # NuGet Packages Directory
97 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
98 | packages/
99 | lib/
100 | !NuGet.exe
101 |
102 | # Windows Azure Build Output
103 | csx
104 | *.build.csdef
105 |
106 | # Windows Store app package directory
107 | AppPackages/
108 |
109 | # Others
110 | sql/
111 | *.Cache
112 | ClientBin/
113 | [Ss]tyle[Cc]op.*
114 | ~$*
115 | *~
116 | *.dbmdl
117 | *.[Pp]ublish.xml
118 | *.pfx
119 | *.publishsettings
120 | *.nupkg
121 | project.lock.json
122 |
123 | # RIA/Silverlight projects
124 | Generated_Code/
125 |
126 | # Backup & report files from converting an old project file to a newer
127 | # Visual Studio version. Backup files are not needed, because we have git ;-)
128 | _UpgradeReport_Files/
129 | Backup*/
130 | UpgradeLog*.XML
131 | UpgradeLog*.htm
132 |
133 | # SQL Server files
134 | App_Data/*.mdf
135 | App_Data/*.ldf
136 |
137 | # Windows image file caches
138 | Thumbs.db
139 | ehthumbs.db
140 |
141 | # Folder config file
142 | Desktop.ini
143 |
144 | # Recycle Bin used on file shares
145 | $RECYCLE.BIN/
146 |
147 | # Mac crap
148 | .DS_Store
149 |
--------------------------------------------------------------------------------
/FontLink Settings.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.421
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FontLink Settings", "FontLink Settings\FontLink Settings.csproj", "{5040C250-CC53-4C39-93AA-913B1BF723F6}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {5040C250-CC53-4C39-93AA-913B1BF723F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {5040C250-CC53-4C39-93AA-913B1BF723F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {5040C250-CC53-4C39-93AA-913B1BF723F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {5040C250-CC53-4C39-93AA-913B1BF723F6}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {255B3250-81B3-491E-BC52-FC39818B7F19}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/FontLink Settings/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/FontLink Settings/App.xaml:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/FontLink Settings/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Configuration;
4 | using System.Data;
5 | using System.Linq;
6 | using System.Threading.Tasks;
7 | using System.Windows;
8 |
9 | namespace FontLinkSettings
10 | {
11 | public partial class App : Application
12 | {
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/FontLink Settings/FallbackTemplateSelector.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Windows;
3 | using System.Windows.Controls;
4 |
5 | namespace FontLinkSettings
6 | {
7 | internal class FallbackTemplateSelector : DataTemplateSelector
8 | {
9 | public override DataTemplate SelectTemplate(Object item, DependencyObject container)
10 | {
11 | if (container is FrameworkElement root &&
12 | item is FontLinkFallback fallback)
13 | {
14 | if (fallback.GDISize == 0 && fallback.DirectXSize == 0)
15 | {
16 | return root.FindResource("Fallback") as DataTemplate;
17 | }
18 |
19 | return root.FindResource("FallbackWithSizes") as DataTemplate;
20 | }
21 |
22 | return null;
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/FontLink Settings/FodyWeavers.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/FontLink Settings/FodyWeavers.xsd:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with line breaks
13 |
14 |
15 |
16 |
17 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with line breaks.
18 |
19 |
20 |
21 |
22 | A list of unmanaged 32 bit assembly names to include, delimited with line breaks.
23 |
24 |
25 |
26 |
27 | A list of unmanaged 64 bit assembly names to include, delimited with line breaks.
28 |
29 |
30 |
31 |
32 | The order of preloaded assemblies, delimited with line breaks.
33 |
34 |
35 |
36 |
37 |
38 | This will copy embedded files to disk before loading them into memory. This is helpful for some scenarios that expected an assembly to be loaded from a physical file.
39 |
40 |
41 |
42 |
43 | Controls if .pdbs for reference assemblies are also embedded.
44 |
45 |
46 |
47 |
48 | Embedded assemblies are compressed by default, and uncompressed when they are loaded. You can turn compression off with this option.
49 |
50 |
51 |
52 |
53 | As part of Costura, embedded assemblies are no longer included as part of the build. This cleanup can be turned off.
54 |
55 |
56 |
57 |
58 | Costura by default will load as part of the module initialization. This flag disables that behavior. Make sure you call CosturaUtility.Initialize() somewhere in your code.
59 |
60 |
61 |
62 |
63 | Costura will by default use assemblies with a name like 'resources.dll' as a satellite resource and prepend the output path. This flag disables that behavior.
64 |
65 |
66 |
67 |
68 | A list of assembly names to exclude from the default action of "embed all Copy Local references", delimited with |
69 |
70 |
71 |
72 |
73 | A list of assembly names to include from the default action of "embed all Copy Local references", delimited with |.
74 |
75 |
76 |
77 |
78 | A list of unmanaged 32 bit assembly names to include, delimited with |.
79 |
80 |
81 |
82 |
83 | A list of unmanaged 64 bit assembly names to include, delimited with |.
84 |
85 |
86 |
87 |
88 | The order of preloaded assemblies, delimited with |.
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | 'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.
97 |
98 |
99 |
100 |
101 | A comma-separated list of error codes that can be safely ignored in assembly verification.
102 |
103 |
104 |
105 |
106 | 'false' to turn off automatic generation of the XML Schema file.
107 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/FontLink Settings/FontLink Settings.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {5040C250-CC53-4C39-93AA-913B1BF723F6}
8 | WinExe
9 | FontLinkSettings
10 | FontLink Settings
11 | v4.7.2
12 | 512
13 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
14 | 4
15 | true
16 | true
17 |
18 |
19 | AnyCPU
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 | false
28 |
29 |
30 | AnyCPU
31 | pdbonly
32 | true
33 | bin\Release\
34 |
35 |
36 | prompt
37 | 4
38 | false
39 |
40 |
41 | Resources\App.ico
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 | 4.0
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 | MSBuild:Compile
64 | Designer
65 |
66 |
67 |
68 | MSBuild:Compile
69 | Designer
70 |
71 |
72 | App.xaml
73 | Code
74 |
75 |
76 |
77 |
78 | MainWindow.xaml
79 | Code
80 |
81 |
82 |
83 |
84 | Code
85 |
86 |
87 | True
88 | True
89 | Resources.resx
90 |
91 |
92 | True
93 | Settings.settings
94 | True
95 |
96 |
97 | PublicResXFileCodeGenerator
98 | Resources.Designer.cs
99 |
100 |
101 | SettingsSingleFileGenerator
102 | Settings.Designer.cs
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | 3.3.2
111 |
112 |
113 | 1.1.0
114 |
115 |
116 | 2.6.3
117 | runtime; build; native; contentfiles; analyzers
118 | all
119 |
120 |
121 | 1.0.0
122 |
123 |
124 |
125 |
126 |
127 |
128 |
--------------------------------------------------------------------------------
/FontLink Settings/FontLinkFallback.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace FontLinkSettings
4 | {
5 | internal class FontLinkFallback
6 | {
7 | public String Typeface { get; set; }
8 | public String Collection { get; set; }
9 | public Int32 GDISize { get; set; }
10 | public Int32 DirectXSize { get; set; }
11 |
12 | public override String ToString()
13 | {
14 | return $"{Typeface} ({Collection})";
15 | }
16 |
17 | public String GDISizeString => $"GDI Size: {GDISize}";
18 | public String DirectXSizeString => $"Direct2D Size: {DirectXSize}";
19 |
20 | public String ExportString
21 | {
22 | get
23 | {
24 | if (GDISize == 0 || DirectXSize == 0)
25 | {
26 | return $"{Collection},{Typeface}";
27 | }
28 |
29 | return $"{Collection},{Typeface},{GDISize},{DirectXSize}";
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/FontLink Settings/MainWindow.xaml:
--------------------------------------------------------------------------------
1 |
18 |
19 |
21 |
22 |
24 |
26 |
28 |
30 |
32 |
33 |
34 |
35 |
37 |
38 |
40 |
41 |
42 |
43 |
45 |
46 |
47 |
49 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
60 |
65 |
70 |
71 |
72 |
73 |
75 |
76 |
77 |
79 |
80 |
85 |
86 |
89 |
90 |
101 |
102 |
108 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/FontLink Settings/MainWindow.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.Globalization;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Security;
7 | using System.Windows;
8 | using System.Windows.Controls;
9 |
10 | using FontLinkSettings.Utilities;
11 |
12 | using Microsoft.Win32;
13 |
14 | using Ookii.Dialogs.Wpf;
15 |
16 | namespace FontLinkSettings
17 | {
18 | public partial class MainWindow : Window
19 | {
20 | private RegistryKey _parent;
21 | private ObservableCollection _fallbacks;
22 |
23 | public void ShowErrorDialog(String heading, String body, Boolean allowElevation = false)
24 | {
25 | var dialog = new TaskDialog
26 | {
27 | AllowDialogCancellation = false,
28 | MainIcon = TaskDialogIcon.Error,
29 | WindowTitle = "FontLink Settings",
30 | MainInstruction = heading,
31 | Content = body +
32 | (allowElevation
33 | ? Environment.NewLine +
34 | Environment.NewLine +
35 | "Try restart the application as administrator."
36 | : String.Empty),
37 | ButtonStyle = allowElevation
38 | ? TaskDialogButtonStyle.CommandLinks
39 | : TaskDialogButtonStyle.Standard,
40 | };
41 |
42 | if (allowElevation)
43 | {
44 | dialog.Buttons.Add(new TaskDialogButton
45 | {
46 | ButtonType = ButtonType.Custom,
47 | Text = "Run as administrator.",
48 | CommandLinkNote = "Verification of login credentials may be required.",
49 | ElevationRequired = true,
50 | Default = false
51 | });
52 | dialog.Buttons.Add(new TaskDialogButton
53 | {
54 | ButtonType = ButtonType.Custom,
55 | Text = "Go back.",
56 | Default = true
57 | });
58 | }
59 | else
60 | {
61 | dialog.Buttons.Add(new TaskDialogButton
62 | {
63 | ButtonType = ButtonType.Ok
64 | });
65 | }
66 |
67 | if (dialog.ShowDialog(this).Text.StartsWith("R", StringComparison.InvariantCultureIgnoreCase))
68 | {
69 | Hide();
70 | SecurityHelpers.RestartAsAdmin();
71 | }
72 | }
73 |
74 | public void ShowInfoDialog(String heading, String body)
75 | {
76 | var dialog = new TaskDialog
77 | {
78 | AllowDialogCancellation = false,
79 | MainIcon = TaskDialogIcon.Information,
80 | WindowTitle = "FontLink Settings",
81 | MainInstruction = heading,
82 | Content = body,
83 | ButtonStyle = TaskDialogButtonStyle.Standard,
84 | };
85 | dialog.Buttons.Add(new TaskDialogButton
86 | {
87 | ButtonType = ButtonType.Close
88 | });
89 | dialog.ShowDialog(this);
90 | }
91 |
92 | public MainWindow()
93 | {
94 | InitializeComponent();
95 | _fallbacks = new ObservableCollection();
96 | }
97 |
98 | private void OnWindowLoaded(Object sender, RoutedEventArgs e)
99 | {
100 | var dialog = new TaskDialog
101 | {
102 | AllowDialogCancellation = false,
103 | MainIcon = TaskDialogIcon.Warning,
104 | WindowTitle = "FontLink Settings",
105 | MainInstruction = "FontLinks Are System Settings Saved in the Windows Registry",
106 | Content = "The application will read from the Windows Registry but will not perform " +
107 | "writes without explicit user interactions." +
108 | Environment.NewLine +
109 | Environment.NewLine +
110 | "Changing system settings affects all programs and all users on this " +
111 | "computer. Please note that improper configuration may cause issues, " +
112 | "such as jumbled texts, application crashes and severe system instability. " +
113 | "Do not save any change unless you know what you are doing!",
114 | ButtonStyle = TaskDialogButtonStyle.CommandLinks
115 | };
116 | dialog.Buttons.Add(new TaskDialogButton
117 | {
118 | ButtonType = ButtonType.Custom,
119 | Text = "I understand the risk!",
120 | CommandLinkNote = "Continue to the application." +
121 | (SecurityHelpers.IsRunningAsAdmin()
122 | ? String.Empty
123 | : Environment.NewLine +
124 | "Administrative privilege may be required."),
125 | Default = false
126 | });
127 | dialog.Buttons.Add(new TaskDialogButton
128 | {
129 | ButtonType = ButtonType.Custom,
130 | Text = "Oh shit, quit now!",
131 | CommandLinkNote = "This scares the hell out of me.",
132 | Default = true
133 | });
134 |
135 | if (!dialog.ShowDialog(this).Text.StartsWith("I", StringComparison.InvariantCulture))
136 | {
137 | Close();
138 | return;
139 | }
140 |
141 | try
142 | {
143 | _parent = Registry.LocalMachine?.OpenSubKey("Software")?.OpenSubKey("Microsoft")
144 | ?.OpenSubKey("Windows NT")?.OpenSubKey("CurrentVersion")
145 | ?.OpenSubKey("FontLink")?.OpenSubKey("SystemLink");
146 |
147 | BaseFont.ItemsSource = _parent?.GetValueNames();
148 | }
149 | catch (SecurityException exception)
150 | {
151 | ShowErrorDialog("System.SecurityException",
152 | exception.Message, true);
153 | Close();
154 | }
155 |
156 | AltFonts.ItemsSource = _fallbacks;
157 | }
158 |
159 | private void OnBaseFontSelected(Object sender, SelectionChangedEventArgs e)
160 | {
161 | Save.IsEnabled = false;
162 |
163 | if (!(BaseFont.SelectedItem is String key)) return;
164 |
165 | try
166 | {
167 | if (!(_parent.GetValue(key) is String[] strings))
168 | {
169 | throw new InvalidOperationException("Registry format unrecognized.");
170 | }
171 |
172 | _fallbacks.Clear();
173 | foreach (var value in strings)
174 | {
175 | var parts = value.Split(',');
176 |
177 | var alt = new FontLinkFallback
178 | {
179 | Collection = parts[0],
180 | Typeface = parts[1]
181 | };
182 |
183 | if (parts.Length > 2)
184 | {
185 | alt.GDISize = Int32.Parse(parts[2], new NumberFormatInfo());
186 | alt.DirectXSize = Int32.Parse(parts[3], new NumberFormatInfo());
187 | }
188 |
189 | _fallbacks.Add(alt);
190 |
191 | Save.IsEnabled = true;
192 | }
193 | }
194 | catch (SecurityException exception)
195 | {
196 | ShowErrorDialog("System.SecurityException",
197 | exception.Message, true);
198 | }
199 | catch (IOException exception)
200 | {
201 | ShowErrorDialog("System.IOException",
202 | exception.Message);
203 | }
204 | catch (UnauthorizedAccessException exception)
205 | {
206 | ShowErrorDialog("System.UnauthorizedAccessException",
207 | exception.Message);
208 | }
209 | catch (InvalidOperationException exception)
210 | {
211 | ShowErrorDialog("System.InvalidOperationException",
212 | exception.Message);
213 | }
214 | }
215 |
216 | private void OnWindowClosed(Object sender, EventArgs e)
217 | {
218 | _parent?.Dispose();
219 | }
220 |
221 | private void OnSaveSettings(Object sender, RoutedEventArgs e)
222 | {
223 | var key = BaseFont.SelectedItem as String;
224 | var strings = _fallbacks.Select(x => x.ExportString).ToArray();
225 |
226 | var dialog = new TaskDialog
227 | {
228 | AllowDialogCancellation = false,
229 | MainIcon = TaskDialogIcon.Warning,
230 | WindowTitle = "FontLink Settings",
231 | MainInstruction = "Save These Settings?",
232 | Content = "Registry key:" +
233 | Environment.NewLine +
234 | "HKEY_LOCAL_MACHINE\\...\\FontLink\\SystemLink\\" +
235 | key +
236 | Environment.NewLine +
237 | Environment.NewLine +
238 | "Multi-String (REG_MULTI_SZ) value:" +
239 | Environment.NewLine +
240 | String.Join(Environment.NewLine, strings),
241 | ButtonStyle = TaskDialogButtonStyle.CommandLinks
242 | };
243 | dialog.Buttons.Add(new TaskDialogButton
244 | {
245 | ButtonType = ButtonType.Custom,
246 | Text = "Yes, save to Registry.",
247 | CommandLinkNote = "The Registry key above will be modified.",
248 | Default = false,
249 | ElevationRequired = true
250 | });
251 | dialog.Buttons.Add(new TaskDialogButton
252 | {
253 | ButtonType = ButtonType.Custom,
254 | Text = "No, go back!",
255 | CommandLinkNote = "I am not ready to risk it."
256 | });
257 |
258 | if (!dialog.ShowDialog(this).Text.StartsWith("Y", StringComparison.InvariantCulture))
259 | {
260 | return;
261 | }
262 |
263 | try
264 | {
265 | using (var writable = Registry.LocalMachine?.OpenSubKey("Software")?.OpenSubKey("Microsoft")
266 | ?.OpenSubKey("Windows NT")?.OpenSubKey("CurrentVersion")
267 | ?.OpenSubKey("FontLink")?.OpenSubKey("SystemLink", true))
268 | {
269 | if (writable == null)
270 | {
271 | throw new InvalidOperationException("Error opening the registry with write access.");
272 | }
273 |
274 | writable.SetValue(key, strings, RegistryValueKind.MultiString);
275 | }
276 |
277 | ShowInfoDialog($"FontLink Entry for {key} Saved.",
278 | "Sign out and back in to see changes; or keep working on other settings.");
279 | }
280 | catch (SecurityException exception)
281 | {
282 | ShowErrorDialog("System.SecurityException",
283 | exception.Message, true);
284 | }
285 | catch (IOException exception)
286 | {
287 | ShowErrorDialog("System.IOException",
288 | exception.Message);
289 | }
290 | catch (UnauthorizedAccessException exception)
291 | {
292 | ShowErrorDialog("System.UnauthorizedAccessException",
293 | exception.Message);
294 | }
295 | catch (InvalidOperationException exception)
296 | {
297 | ShowErrorDialog("System.InvalidOperationException",
298 | exception.Message);
299 | }
300 | }
301 | }
302 | }
303 |
--------------------------------------------------------------------------------
/FontLink Settings/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 | using System.Windows;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FontLink Settings")]
9 | [assembly: AssemblyDescription("An intuitive GUI to modify FontLink registries.")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("Yi Ding")]
12 | [assembly: AssemblyProduct("FontLink Settings")]
13 | [assembly: AssemblyCopyright("Copyright © Yi Ding 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | //In order to begin building localizable applications, set
23 | //CultureYouAreCodingWith in your .csproj file
24 | //inside a . For example, if you are using US english
25 | //in your source files, set the to en-US. Then uncomment
26 | //the NeutralResourceLanguage attribute below. Update the "en-US" in
27 | //the line below to match the UICulture setting in the project file.
28 |
29 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
30 |
31 |
32 | [assembly: ThemeInfo(
33 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
34 | //(used if a resource is not found in the page,
35 | // or application resource dictionaries)
36 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
37 | //(used if a resource is not found in the page,
38 | // app, or any theme specific resource dictionaries)
39 | )]
40 |
41 |
42 | // Version information for an assembly consists of the following four values:
43 | //
44 | // Major Version
45 | // Minor Version
46 | // Build Number
47 | // Revision
48 | //
49 | // You can specify all the values or you can default the Build and Revision Numbers
50 | // by using the '*' as shown below:
51 | // [assembly: AssemblyVersion("1.0.*")]
52 | [assembly: AssemblyVersion("1.0.1.0")]
53 | [assembly: AssemblyFileVersion("1.0.1.0")]
54 |
--------------------------------------------------------------------------------
/FontLink Settings/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FontLinkSettings.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("FontLinkSettings.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized resource of type System.Drawing.Icon similar to (Icon).
65 | ///
66 | public static System.Drawing.Icon App {
67 | get {
68 | object obj = ResourceManager.GetObject("App", resourceCulture);
69 | return ((System.Drawing.Icon)(obj));
70 | }
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/FontLink Settings/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 |
122 | ..\Resources\App.ico;System.Drawing.Icon, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
123 |
124 |
--------------------------------------------------------------------------------
/FontLink Settings/Properties/Settings.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace FontLinkSettings.Properties {
12 |
13 |
14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")]
16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
17 |
18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
19 |
20 | public static Settings Default {
21 | get {
22 | return defaultInstance;
23 | }
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/FontLink Settings/Properties/Settings.settings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/FontLink Settings/Resources/App.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/VaslD/FontLink-GUI/47457ef4d4dcd69f8249c22720d7e690d6a58bf6/FontLink Settings/Resources/App.ico
--------------------------------------------------------------------------------
/FontLink Settings/Utilities/SecurityHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Reflection;
4 | using System.Security;
5 | using System.Security.Principal;
6 | using System.Windows;
7 |
8 | namespace FontLinkSettings.Utilities
9 | {
10 | public static class SecurityHelpers
11 | {
12 | public static Boolean IsRunningAsAdmin()
13 | {
14 | try
15 | {
16 | using (var identity = WindowsIdentity.GetCurrent())
17 | {
18 | var principal = new WindowsPrincipal(identity);
19 | return principal.IsInRole(WindowsBuiltInRole.Administrator);
20 | }
21 | }
22 | catch (SecurityException)
23 | {
24 | return false;
25 | }
26 | }
27 |
28 | public static void RestartAsAdmin()
29 | {
30 | var executable = Assembly.GetExecutingAssembly().Location;
31 |
32 | var request = new ProcessStartInfo(executable)
33 | {
34 | Verb = "runas"
35 | };
36 | Process.Start(request);
37 | Application.Current.Shutdown(0);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/License.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (C) 2019, Yi Ding
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | # FontLink Settings
2 |
3 | It looks like this project is getting a bit attention. This revision should clear things up. Please do pull and read this update before messing with your computer using this program. It may or may not be something you want.
4 |
5 | ## FontLink, Explained
6 |
7 | **FontLink** is a series of Windows [Registry](https://docs.microsoft.com/en-us/windows/win32/sysinfo/registry) keys controlling Font Linking, a technology that combines multiple typefaces (fonts) behind-the-scene to substitue missing glyphs (characters) in the currently selected/used typeface.
8 |
9 | You can read the full documentation in [the Font Linking section of Font Technology](https://docs.microsoft.com/en-us/globalization/input/font-technology).
10 |
11 | ## Notes on Terms
12 |
13 | *If you're reading a translation (non-English version) of this document, please skip this section as whatever I say here may not apply to other languages.*
14 |
15 | To be clear, for most people who are not in the design and print industry, **the word *font* does not originally mean what we think it means**. In typography, *font* is a combination of a typeface (e.g. Times New Roman), a size (e.g. 12 pt) and other attributes (such as weight). So "Times New Roman, 12 pt, bold" is a *font*; while "Times New Roman" is not a *font*, it's only a *typeface*. Similarly, "Segoe UI" is not a *font*, neither is "Arial" or "Microsoft JhengHei".
16 |
17 | But in this article, (and many, many others on the Internet,) ***font* is now a catch-all phrase** used colloquially to mean: (1) a typeface (e.g. "Times New Roman"), or (2) a typeface with certain size and attributes (e.g. "Times New Roman, 12 pt, bold"), or rarely (3) just the size/attributes of an unspecified typeface (e.g. "any 12 pt font", "a bolder font"). Much like the widely misused term [*RJ45*](https://en.wikipedia.org/wiki/Registered_jack#Similar_jacks_and_unofficial_names) (which is just a generic 8P8C connector).
18 |
19 | Just so you know.
20 |
21 | ## See It in Action
22 |
23 | When you set your Windows display language to English (or many other languages that use Latin script), the default user interface font is Segoe UI ("see-go, U-I"). Segoe font family covers most glyphs used in languages that have European root.
24 |
25 | When Windows encounters a glyph that cannot be found in Segoe family, for example the CJK-character "中", in order to render this glyph Windows searches typefaces defined in the *FontLink* Registry for Segoe UI (that is, *HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\FontLink\SystemLink\Segoe UI*) for a substitute glyph. The first entry is Tahoma, not a font designed for CJK scripts; so continue on, the character "中" would be found in either Meiryo (for Japanese) or SimSun (for Chinese), depends on font availability.
26 |
27 | Problem is, [Microsoft did many redesigns of typefaces throughout releases of Windows](https://docs.microsoft.com/en-us/globalization/input/font-support). Neither Meiryo or SimSun is the recommended user interface font for CJK characters anymore. In Windows 10, the default font for CJK scripts are:
28 |
29 | - **Microsoft YaHei UI** for Chinese (Simplified)
30 | - **Microsoft JhengHei UI** for Chinese (Traditional)
31 | - **Yu Gothic UI** for Japanese
32 | - **Malgun Gothic** for Korean
33 |
34 | That's why CJK characters in the following screenshot look so out of place when mixed with Latin characters:
35 |
36 |
37 |
38 | Using this program, prioritizing any of the above font over Meiryo and SimSun as a substitute for Segoe UI produces the following screenshot (after a logout):
39 |
40 |
41 |
42 | You can clearly see that the font for CJK characters is changed to a much more look-alike version, while the English text remains from Segoe UI.
43 |
44 | ## Pros & Cons
45 |
46 | Font Linking works great only when you're dealing with multiple languages that use different scripts with no intersecting Unicode codepoints. It doesn't solve all multilingual problems. And frankly, with the rise of Unicode, those problems remain unsolvable.
47 |
48 | "Unihan" is one of those problems. When the same glyph/codepoint is used in different scripts and all of these scripts are mixed into one sentence. Windows lacks the necessary information to pick *the best* fallback for this glyph. For example, the character "中" is used in both modern day Simplified and Traditional Chinese, and Japanese. All three scripts have different typefaces to render "中" from, but in Font Linking, you can only pick one typeface (YaHei, JhengHei, or Yu Gothic) to render all "中"s. That means if you prioritized Microsoft YaHei in FontLink Registry, "中" will always to rendered using YaHei even when you're seeing Japanese file names, which should be rendered using Yu Gothic.
49 |
50 | **Font Linking also works across Windows. There is no fine-tune per app switch.** Whenever an application (e.g. File Explorer, Notepad) requests a character from a font that has no such character, Windows uses FontLink Registry to do its magic. However, many apps supply typefaces internally or define their own fallback mechanism; these apps will not be affected by Font Linking initially.
51 |
52 | ## How to Use
53 |
54 | This example shows how to use this program to achieve the result in the screenshots.
55 |
56 | 1. You need to identify the font currently being used/selected in an app. That is, the font that's missing glyphs. In this example, it's the default user interface font for English editions of Windows: Segoe UI.
57 |
58 | 2. Launch the program (preferably with Administrator privilege). Find and select Segoe UI from top dropdown.
59 |
60 |
61 |
62 | 3. The list below the dropdown shows the current Registry reading of FontLink fallback orders. Adjust the list by dragging and dropping entries around. **Note that entries with the same name (usually one with and one without GDI attributes) must go together when reordering. Otherwise legacy apps using older technology may not observe new changes.**
63 |
64 | These are the recommended preferences for mixing English and Simplified Chinese characters:
65 |
66 |
67 |
68 | 4. Finally, click *Save Current Settings to Registry*. You may be asked to review the raw Registry value, or to relaunch the program with Administrative privilege if not done so before.
69 |
70 | 5. To see your changes, logout and log back in. **Note that this may close all currently running programs, and you may lose unsaved work.**
71 |
72 | ------
73 |
74 | At step 3, if you frequently mix English with Traditional Chinese characters, you may want to use these preferences:
75 |
76 |
77 |
78 | And this is for mixing English with Japanese characters:
79 |
80 |
81 |
--------------------------------------------------------------------------------