SetCurrentConsoleFontEx 不适用于长字体名称
SetCurrentConsoleFontEx isn't working for long font names
对于 16 个字符或更长的字体名称,我无法让它工作,但控制台本身显然没有此限制。有谁知道一种编程方式来设置将与内置 "Lucida Sans Typewriter" 或开源 "Fira Code Retina" 一起使用的字体?
以下代码有效:
我从各个地方复制了 PInvoke 代码,特别是 the PowerShell console host, and the Microsoft Docs
请注意,CONSOLE_FONT_INFOEX and SetCurrentConsoleFontEx 的相关文档并未提及这一点,该结构将字体定义为大小为 32 的 WCHAR 字段...
另请注意,这不是限制,但是来自控制台对话框的限制,即字体必须具有 True Type 轮廓,并且必须真正固定宽度。使用此 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);
}
}
}
您可以在 PowerShell window 中使用它,方法是使用 Add-Type
和该代码,然后执行如下操作:
[ConsoleHelper]::SetCurrentFont("Consolas", 16)
[ConsoleHelper]::SetCurrentFont("Lucida Console", 12)
然后,使用您的控制台 "Properties" 对话框并手动切换到 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, a font that has exactly 16 characters in the name -- and I have a little bit more code than what's above in a gist here 这个问题,如果你愿意尝试的话...
我在控制台 API 中找到了一个 bug。从 Windows 10(内部人员)build 18267 开始修复。
在那个版本之前,没有办法绕过它——除了使用名称较短的字体,或者使用实际的 window 属性面板来设置它。
原来的 post 代码现在可以工作了...
对于 16 个字符或更长的字体名称,我无法让它工作,但控制台本身显然没有此限制。有谁知道一种编程方式来设置将与内置 "Lucida Sans Typewriter" 或开源 "Fira Code Retina" 一起使用的字体?
以下代码有效:
我从各个地方复制了 PInvoke 代码,特别是 the PowerShell console host, and the Microsoft Docs
请注意,CONSOLE_FONT_INFOEX and SetCurrentConsoleFontEx 的相关文档并未提及这一点,该结构将字体定义为大小为 32 的 WCHAR 字段...
另请注意,这不是限制,但是来自控制台对话框的限制,即字体必须具有 True Type 轮廓,并且必须真正固定宽度。使用此 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);
}
}
}
您可以在 PowerShell window 中使用它,方法是使用 Add-Type
和该代码,然后执行如下操作:
[ConsoleHelper]::SetCurrentFont("Consolas", 16)
[ConsoleHelper]::SetCurrentFont("Lucida Console", 12)
然后,使用您的控制台 "Properties" 对话框并手动切换到 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, a font that has exactly 16 characters in the name -- and I have a little bit more code than what's above in a gist here 这个问题,如果你愿意尝试的话...
我在控制台 API 中找到了一个 bug。从 Windows 10(内部人员)build 18267 开始修复。
在那个版本之前,没有办法绕过它——除了使用名称较短的字体,或者使用实际的 window 属性面板来设置它。
原来的 post 代码现在可以工作了...