You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 23:06:05