C# Winform中如何获取包含OpenType字体在内的系统字体列表
C# Winform 获取含OpenType在内的全量系统字体列表方案
InstalledFontCollection 是GDI+封装的类,本身设计上仅支持枚举TrueType格式字体,确实无法覆盖OpenType(.otf)字体。要获取全量系统字体列表可以用以下两种实现方案:
方案1:读取系统注册表获取(实现最简单)
Windows系统会把所有已安装字体的信息统一存在注册表的两个固定路径下,直接读取即可获取完整列表:
- 全局安装的字体路径:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts - 当前用户单独安装的字体路径:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts
代码示例:
using Microsoft.Win32; using System.Collections.Generic; public static List<string> GetAllInstalledFonts() { List<string> fontNames = new List<string>(); // 读取全局字体注册表项 using (RegistryKey localMachineKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", false)) { foreach (string valueName in localMachineKey.GetValueNames()) { // 去掉字体名称后面的"(TrueType)"、"(OpenType)"后缀 string fontName = valueName.Split('(')[0].Trim(); if (!fontNames.Contains(fontName)) { fontNames.Add(fontName); } } } // 读取当前用户字体注册表项 using (RegistryKey currentUserKey = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts", false)) { if (currentUserKey != null) { foreach (string valueName in currentUserKey.GetValueNames()) { string fontName = valueName.Split('(')[0].Trim(); if (!fontNames.Contains(fontName)) { fontNames.Add(fontName); } } } } return fontNames; }
注意:该方案不需要管理员权限,普通用户权限即可正常读取两个注册表位置的内容。
方案2:调用Win32 API EnumFontFamiliesEx实现(更标准)
如果需要获取更完整的字体元信息,可以调用Windows原生API枚举字体,支持同时识别TTF和OTF格式:
代码示例:
using System; using System.Collections.Generic; using System.Drawing; using System.Runtime.InteropServices; public static class FontEnumerator { [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private class LOGFONT { public int lfHeight = 0; public int lfWidth = 0; public int lfEscapement = 0; public int lfOrientation = 0; public int lfWeight = 0; public byte lfItalic = 0; public byte lfUnderline = 0; public byte lfStrikeOut = 0; public byte lfCharSet = 1; public byte lfOutPrecision = 0; public byte lfClipPrecision = 0; public byte lfQuality = 0; public byte lfPitchAndFamily = 0; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string lfFaceName = string.Empty; } private delegate int EnumFontFamExProc(IntPtr lpelfe, IntPtr lpntme, uint FontType, IntPtr lParam); [DllImport("gdi32.dll", CharSet = CharSet.Auto)] private static extern int EnumFontFamiliesEx(IntPtr hdc, [In] LOGFONT lpLogfont, EnumFontFamExProc lpEnumFontFamExProc, IntPtr lParam, uint dwFlags); public static List<string> GetAllFontNames() { List<string> fontNames = new List<string>(); using (Graphics g = Graphics.FromHwnd(IntPtr.Zero)) { IntPtr hdc = g.GetHdc(); LOGFONT lf = new LOGFONT(); lf.lfCharSet = 1; // DEFAULT_CHARSET EnumFontFamiliesEx(hdc, lf, (IntPtr lpelfe, IntPtr lpntme, uint FontType, IntPtr lParam) => { LOGFONT logFont = (LOGFONT)Marshal.PtrToStructure(lpelfe, typeof(LOGFONT)); string fontName = logFont.lfFaceName.Trim(); if (!fontNames.Contains(fontName)) { fontNames.Add(fontName); } return 1; // 继续枚举 }, IntPtr.Zero, 0); g.ReleaseHdc(hdc); } return fontNames; } }
以上两种方案都可以完整获取包含OpenType在内的所有系统已安装字体列表,满足仅获取列表不需要渲染的需求。
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

