如何以编程方式将控制台字体设置为Lucida?

时间:2017-02-17 22:55:27

标签: c++ windows mingw console-application

Lucida Console在Windows 7上预装了TTF字体,我想在控制台应用程序中以编程方式设置它。

  1. 出于某种原因,SetCurrentConsoleFontEx“甚至没有在此范围内声明”。我#include <windows.h>应该在哪里定义。

  2. 我会在CONSOLE_FONT_INFOEX中添加什么内容?

  3. #define _WIN32_WINNT 0x0601正如@Alf建议的那样,没有效果

  4. 很容易右键单击控制台标题并在那里手动选择字体,但我宁愿在代码中这样做。

    它应该在Windows XP +上运行,我在Windows 7上使用MinGW g ++ 4.8.1。

1 个答案:

答案 0 :(得分:1)

如果设置SetCurrentConsoleFontEx后即使CONSOLE_FONT_INFOEX_WIN32_WINNT不存在,那么您使用的是过时的SDK。 MinGW并不少见,因为它使用非官方的第三方头文件。

在Windows上处理控制台字体是有问题的,因为控制台将其字体存储在内部数组中。您可能还必须使用一些未记录的函数。

在Vista上,以后只需要拨打SetCurrentConsoleFontEx。问题当然是文档非常糟糕,CONSOLE_FONT_INFOEX结构用于Set和Get函数,而不告诉你使用了哪些成员。

设置时似乎只需要设置cbSizeFaceName,其他所有内容都可以为零:

HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_FONT_INFOEX cfie;
ZeroMemory(&cfie, sizeof(cfie));
cfie.cbSize = sizeof(cfie);
lstrcpyW(cfie.FaceName, L"Lucida Console");
SetCurrentConsoleFontEx(hStdOut, false, &cfie);

如果要设置特定字体大小,可以设置dwFontSize.Y。小心FontFamily,如果将其设置为错误的值,Windows将恢复为默认的终端字体。

在Vista之前的系统中,您可以在字体数组中访问的唯一内容是:

#if 1 // Using old SDK?
typedef struct _CONSOLE_FONT_INFOEX {
ULONG cbSize;
DWORD nFont;
COORD dwFontSize;
UINT FontFamily;
UINT FontWeight;
WCHAR FaceName[LF_FACESIZE];
} CONSOLE_FONT_INFOEX, *PCONSOLE_FONT_INFOEX;
typedef BOOL (WINAPI*SETCURRENTCONSOLEFONTEX)(HANDLE hConsoleOutput,BOOL bMaximumWindow,CONSOLE_FONT_INFOEX*lpConsoleCurrentFontEx);
SETCURRENTCONSOLEFONTEX SetCurrentConsoleFontEx = (SETCURRENTCONSOLEFONTEX) GetProcAddress(LoadLibraryA("KERNEL32"), "SetCurrentConsoleFontEx");
typedef BOOL (WINAPI*GETCURRENTCONSOLEFONTEX)(HANDLE hConsoleOutput,BOOL bMaximumWindow,CONSOLE_FONT_INFOEX*lpConsoleCurrentFontEx);
GETCURRENTCONSOLEFONTEX GetCurrentConsoleFontEx = (GETCURRENTCONSOLEFONTEX) GetProcAddress(LoadLibraryA("KERNEL32"), "GetCurrentConsoleFontEx");
#endif

static DWORD PrintFontInfoNT4(HANDLE hCon)
{
    CONSOLE_FONT_INFO cfi;
    BOOL succ = GetCurrentConsoleFont(hCon, false, &cfi);
    printf("Get succ=%d nFont=%u dwFontSize=%dx%d\n", succ, cfi.nFont, cfi.dwFontSize.X, cfi.dwFontSize.Y);
    return succ ? cfi.nFont : -1;
}

static DWORD PrintFontInfoNT6(HANDLE hCon)
{
    CONSOLE_FONT_INFOEX cfie;
    ZeroMemory(&cfie, sizeof(cfie));
    cfie.cbSize = sizeof(cfie);
    BOOL succ = GetCurrentConsoleFontEx(hCon, false, &cfie);
    printf("GetEx succ=%d nFont=%u size=%dx%d fam=%#x wei=%u name=%ls\n", succ, cfie.nFont, cfie.dwFontSize.X, cfie.dwFontSize.Y, cfie.FontFamily, cfie.FontWeight, cfie.FaceName);
    return succ ? cfie.nFont : -1;
}

static void TestNT4()
{
    HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
    typedef DWORD (WINAPI*GETNUMBEROFCONSOLEFONTS)();
    GETNUMBEROFCONSOLEFONTS GetNumberOfConsoleFonts = (GETNUMBEROFCONSOLEFONTS) GetProcAddress(LoadLibraryA("KERNEL32"), "GetNumberOfConsoleFonts");
    typedef BOOL (WINAPI*SETCONSOLEFONT)(HANDLE hConOut, DWORD nFont);
    SETCONSOLEFONT SetConsoleFont = (SETCONSOLEFONT) GetProcAddress(LoadLibraryA("KERNEL32"), "SetConsoleFont");

    // This is the best you can do on NT/2000/XP/2003 without hacks
    DWORD orgFont = PrintFontInfoNT4(hStdOut);
    printf("GetNumberOfConsoleFonts=%u orgFont=%u\n", GetNumberOfConsoleFonts(), orgFont);
    for (DWORD i = 0, c = GetNumberOfConsoleFonts(); i < c; ++i)
    {
        SetConsoleFont(hStdOut, i);
        PrintFontInfoNT4(hStdOut);
#if _WIN32_WINNT >= 0x0600
        PrintFontInfoNT6(hStdOut);
#endif
        Sleep(1000);
    }
    SetConsoleFont(hStdOut, orgFont); // Restore the original font
}

这是无用的,因为您无法分辨您正在设置哪种字体。如果您仍然坚持在Vista之前的系统上设置字体,那么您必须亲自动手。首先,您需要确定要将更改应用到哪个终端窗口。

终端默认值存储在HKEY_CURRENT_USER\Console下,每个应用程序设置可以存储在子键中。如果应用程序是由快捷方式启动的,则这些默认值可以是overridden

如果您只想更改正在运行的控制台,那么事情变得更加困难,但Windows本身当然知道如何直接设置字体。当您在控制台菜单中选择“属性”并应用字体更改时,您可以看到此操作。这可能会从版本更改为版本,但我相信它使用映射内存和秘密消息。您可以通过在WinDbg中设置断点来开始调查;正确设置符号后,键入bp console!Write* Tab Enter (如果有多个写入函数,则在所有写入函数上设置)。您将不得不弄清楚它正在使用的结构的布局,因此您可能必须在此时应用一个控制台设置并转储/比较内存。

修改

看起来有些人已经想到了这一点。 This bug analysis paper有一个结构定义,我也found a SetConsolePalette function实现了映射的内存技巧。 ReactOS可能不会使用完全相同的实现,但您也可以使用take a look at it

您仍需要在拥有它的系统上调用SetCurrentConsoleFontEx,因为当Windows开始使用conhost.exe时内部可能已更改。