Lucida Console is preinstalled TTF font on Windows 7 and I'd like to programatically set it in console application.
For some reason, SetCurrentConsoleFontEx "is not even declared in this scope". I #include <windows.h> where it should be defined.
What would I put into CONSOLE_FONT_INFOEX?
#define _WIN32_WINNT 0x0601 as @Alf suggests, has no effect
It is easy to right-click on the console title and choose font manually there, but I'd rather do that in code.
It should run on Windows XP+, I use MinGW g++ 4.8.1 on Windows 7.
If SetCurrentConsoleFontEx and CONSOLE_FONT_INFOEX don't exist even after setting _WIN32_WINNT then you are using a outdated SDK. Not uncommon with MinGW because it uses unofficial 3rd-party header files.
Dealing with console fonts on Windows is problematic because the console stores its fonts in a internal array. You might also have to use some undocumented functions.
On Vista and later all that is needed is a call to SetCurrentConsoleFontEx. The problem is of course that the documentation is really bad and the CONSOLE_FONT_INFOEX struct is used for both the Set and Get functions without telling you which members are used.
When setting it only seems to require you to set cbSize and FaceName, everything else can be zero:
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);
If you want to set a specific font size you can set dwFontSize.Y. Be careful with FontFamily, if you set it to the wrong value Windows will revert to the default terminal font.
On pre-Vista systems the only thing you can access in the font array is the size:
#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
}
This is pretty useless because you cannot tell which font you are setting. If you still insist on setting the font on pre-Vista systems you have to get your hands dirty. First you need to decide which terminal windows you want to apply the change to.
The terminal defaults are stored under HKEY_CURRENT_USER\Console and per-app settings can be stored in sub keys. These defaults can be overridden if the application is started by a shortcut.
If you only want to change the console you are running in then things get even harder but Windows itself of course knows how to set the font directly. You can see this in action when you choose "Properties" in a consoles menu and applying a font change. This can probably change from version to version but I believe it uses mapped memory and a secret message. You can begin your investigation by setting a breakpoint in WinDbg; after setting up symbols correctly, type bp console!Write* TabEnter (Set it on all write functions if there is more than one). You will have to figure out the layout of the struct it is using so you might have to apply one console setting at the time and dump/compare the memory.
Edit:
It looks like some people have already figured this out. This bug analysis paper has a struct definition and I also found a SetConsolePalette function that implements the mapped memory trick. ReactOS might not use the exact same implementation but you could also take a look at it.
You still need to call SetCurrentConsoleFontEx on systems that have it because the internals probably changed when Windows started using conhost.exe.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With