SetCurrentConsoleFontEx不适用于长字体名称

Jay*_*kul 6 c# windows console powershell pinvoke

我不能让这个用于16个字符或更长的字体名称,但控制台本身显然没有这个限制.有没有人知道一种程序化的方式来设置与内置的"Lucida Sans打字机"或开源"Fira Code Retina"一起使用的字体?

以下代码有效:

我从各个地方复制了PInvoke代码,特别是PowerShell控制台主机Microsoft Docs

请注意,CONSOLE_FONT_INFOEXSetCurrentConsoleFontEx的相关文档没有谈到这一点,结构将字体定义为大小为32的WCHAR字段...

还要注意什么不是限制,而是从控制台对话框的限制,是字体必须有真正的类型列出,而且必须是真正的固定宽度.使用此API,您可以选择"Times New Roman"等可变宽度字体...

但是,在API中,名称中必须少于 16个字符 - 这是控制台本身没有的限制,可能是API中的错误而不是我的下面的代码

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

[ConsoleHelper]::SetCurrentFont("Consolas", 16)
[ConsoleHelper]::SetCurrentFont("Lucida Console", 12)
Run Code Online (Sandbox Code Playgroud)

然后,使用控制台"属性"对话框并手动切换到Lucida Sans Typewriter...并尝试只更改字体大小,指定相同的字体名称:

[ConsoleHelper]::SetCurrentFont("Lucida Sans Typewriter", 12)
Run Code Online (Sandbox Code Playgroud)

你会得到这样的输出(显示三个设置:之前,我们尝试过,我们得到了什么):

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
Run Code Online (Sandbox Code Playgroud)

你在"之前"值的末尾看到那个奇怪的字符?只要字体长度超过16个字符就会发生这种情况(由于API或编组问题,我得到了垃圾数据).

实际的控制台字体名称显然不受长度限制,但也许不能使用名称长度为16个字符或更长的字体?

为了它的价值,我发现了Fira Code Retina的这个问题,这个字体在名称中只有16个字符 - 如果你想要试验的话,我在这里的代码比上面的代码多一点......

Jay*_*kul 0

我在控制台 API 中发现了一个错误。自 Windows 10(内部版本)18267 起已修复。

在此版本之前,没有办法解决这个问题 - 除非使用名称较短的字体,或使用实际的窗口属性面板来设置它。

原来的邮政编码现在可以使用......