代码之家  ›  专栏  ›  技术社区  ›  Jaykul

SetCurrentConsoleFontEx不适用于长字体名称

  •  6
  • Jaykul  · 技术社区  · 7 年前

    对于16个字符或更长的字体名,我无法做到这一点,但控制台本身显然没有这个限制。有没有人知道一种编程的方式来设置字体,它可以与内置的“Lucida Sans Typewriter”或开源的“Fira Code Retina”一起工作?

    我从不同的地方复制了PInvoke代码,特别是 the PowerShell console host Microsoft Docs

    请注意 CONSOLE_FONT_INFOEX SetCurrentConsoleFontEx 不要谈论这个,结构将字体定义为大小为32的WCHAR字段。。。

    还要注意什么不是限制,而是 控制台对话框的一个限制是字体必须有真正的字体轮廓,并且必须是真正固定的宽度。使用这个API你可以选择可变宽度的字体,比如“Times New Roman”。。。

    但是,在API中,它必须 名称中包含16个字符——这是控制台本身没有的限制,并且 可以 成为API中的一个bug,而不是我下面的代码

    using System;
    using System.Runtime.InteropServices;
    
    public static class ConsoleHelper
    {
        private const int FixedWidthTrueType = 54;
        private const int StandardOutputHandle = -11;
    
        [DllImport("kernel32.dll", SetLastError = true)]
        internal static extern IntPtr GetStdHandle(int nStdHandle);
    
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool SetCurrentConsoleFontEx(IntPtr hConsoleOutput, bool MaximumWindow, ref FontInfo ConsoleCurrentFontEx);
    
        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        internal static extern bool GetCurrentConsoleFontEx(IntPtr hConsoleOutput, bool MaximumWindow, ref FontInfo ConsoleCurrentFontEx);
    
    
        private static readonly IntPtr ConsoleOutputHandle = GetStdHandle(StandardOutputHandle);
    
        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
        public struct FontInfo
        {
            internal int cbSize;
            internal int FontIndex;
            internal short FontWidth;
            public short FontSize;
            public int FontFamily;
            public int FontWeight;
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
            //[MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.wc, SizeConst = 32)]
            public string FontName;
        }
    
        public static FontInfo[] SetCurrentFont(string font, short fontSize = 0)
        {
            Console.WriteLine("Set Current Font: " + font);
    
            FontInfo before = new FontInfo
            {
                cbSize = Marshal.SizeOf<FontInfo>()
            };
    
            if (GetCurrentConsoleFontEx(ConsoleOutputHandle, false, ref before))
            {
    
                FontInfo set = new FontInfo
                {
                    cbSize = Marshal.SizeOf<FontInfo>(),
                    FontIndex = 0,
                    FontFamily = FixedWidthTrueType,
                    FontName = font,
                    FontWeight = 400,
                    FontSize = fontSize > 0 ? fontSize : before.FontSize
                };
    
                // Get some settings from current font.
                if (!SetCurrentConsoleFontEx(ConsoleOutputHandle, false, ref set))
                {
                    var ex = Marshal.GetLastWin32Error();
                    Console.WriteLine("Set error " + ex);
                    throw new System.ComponentModel.Win32Exception(ex);
                }
    
                FontInfo after = new FontInfo
                {
                    cbSize = Marshal.SizeOf<FontInfo>()
                };
                GetCurrentConsoleFontEx(ConsoleOutputHandle, false, ref after);
    
                return new[] { before, set, after };
            }
            else
            {
                var er = Marshal.GetLastWin32Error();
                Console.WriteLine("Get error " + er);
                throw new System.ComponentModel.Win32Exception(er);
            }
        }
    }
    

    您可以在PowerShell窗口中使用 Add-Type 使用这些代码,然后执行如下操作:

    [ConsoleHelper]::SetCurrentFont("Consolas", 16)
    [ConsoleHelper]::SetCurrentFont("Lucida Console", 12)
    

    Lucida Sans Typewriter ... 并尝试更改字体大小,指定相同的字体名称:

    [ConsoleHelper]::SetCurrentFont("Lucida Sans Typewriter", 12)
    

    您将得到如下输出(显示三个设置:之前,我们尝试了什么,我们得到了什么):

    Set Current Font: Lucida Sans Typewriter
    
    FontSize FontFamily FontWeight FontName
    -------- ---------- ---------- --------
          14         54        400 Lucida Sans Typeʈ
          12         54        400 Lucida Sans Typewriter
          12         54        400 Courier New
    

    你看到“before”值后面那个奇怪的字符了吗?每当字体长度超过16个字符时就会发生这种情况(由于API或封送处理中的问题,我得到的是垃圾数据)。

    实际的控制台字体名称显然没有长度限制,但可能无法使用名称为16个字符或更长的字体?

    Fira Code Retina ,一种名称中正好有16个字符的字体--我的代码比上面的要多一点 a gist here

    1 回复  |  直到 7 年前
        1
  •  0
  •   Jaykul    7 年前

    我找到了一个 bug 在控制台API中。它在Windows10(insider)build 18267中修复。

    在此版本之前,除了使用名称较短的字体,或者使用实际的窗口属性面板进行设置之外,没有其他方法可以解决这个问题。

    推荐文章