在C++控制台应用程序中使用Unicode字体

8
如何在我的C++ Windows控制台应用程序中更改字体?
它似乎不使用cmd.exe默认使用的字体(Lucida Console)。当我通过现有的cmd.exe运行我的应用程序(键入name.exe),它看起来像这样:http://dathui.mine.nu/konsol3.png,这是完全正确的。 但是当我单独运行我的应用程序(双击.exe文件)时,它看起来像这样:http://dathui.mine.nu/konsol2.png。 相同的代码,两个不同的外观。
所以现在我想知道如何更改字体,以便无论如何运行它,它都始终显示正确。

编辑:

好的,更多信息。当我只使用这个小片段时:

SetConsoleOutputCP(CP_UTF8);
wchar_t s[] = L"èéøÞǽлљΣæča";
int bufferSize = WideCharToMultiByte(CP_UTF8, 0, s, -1, NULL, 0, NULL, NULL);
char* m = new char[bufferSize]; 
WideCharToMultiByte(CP_UTF8, 0, s, -1, m, bufferSize, NULL, NULL);
wprintf(L"%S", m);

它可以与正确的字体一起使用。但在我的实际应用程序中,我使用WriteConsoleOutput()来打印字符串:

CHAR_INFO* info = new CHAR_INFO[mWidth * mHeight];
for(unsigned int a = 0; a < mWidth*mHeight; ++a) {
    info[a].Char.UnicodeChar = mWorld.getSymbol(mWorldX + (a % mWidth), mWorldY + (a / mWidth));
    info[a].Attributes = mWorld.getColour(mWorldX + (a % mWidth), mWorldY + (a / mWidth));
}
COORD zero;
zero.X = zero.Y = 0;
COORD buffSize;
buffSize.X = mWidth;
buffSize.Y = mHeight;
if(!WriteConsoleOutputW(window, info, buffSize, zero, &rect)) {
    exit(-1);
}

然后它使用了错误的字体。我使用两个不同的窗口,像这样创建:

mHandleA = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 0,
                                     NULL, CONSOLE_TEXTMODE_BUFFER, NULL);

我是否可以为标准输出设置代码页或其他内容?

嗯...奇怪,有一种方法可以检测控制台与双击,但有一些特殊情况。这篇文章是一个很好的开始,但它还不够深入:http://www.codeguru.com/cpp/misc/misc/consoleapps/article.php/c15893/ - Hamish Grubijan
你用哪个编译器? - Sajad Bahmani
也许可以追踪启动代码 - 从 pre main() 开始 - 看看哪些代码实际上正在构建控制台窗口本身?我假设您的 .exe 中必须有一些代码是由编译器/控制台项目提供的,用于检测您的应用程序是否已在控制台中启动,或者如果需要一个控制台,则为您创建一个控制台窗口。这是我的直觉,不是经过研究的事实,但只需几分钟调试即可验证。此时,您可以查看该源代码,并查看您可能需要执行哪些操作才能访问该控制台 HWND,以便以不同的方式设置其字体... - Mordachai
Ipthnc: 听起来有点绕,不过感谢这个提示。SjB: Visual Studio 2008 专业版。Mordachai: 嗯,我在哪里能找到前主代码呢? - dutt
3个回答

4

Windows会将cmd的设置(包括字体)存储在注册表中,使用exe路径作为键。根键是“HKEY_CURRENT_USER\Console”,因此如果您使用regedit查看该键,则应该看到几个以各种exe命名的子键。

要复制现有exe的设置,可以将该键导出到文本文件中,然后编辑文件以更改键名称为您的exe名称,然后重新导入它。

您还可以通过编程方式修改注册表,但我怀疑这不会立即影响您的控制台窗口。


3

1
你可能也想提到 GetStdHandle - http://msdn.microsoft.com/en-us/library/ms683231(VS.85).aspx - Mark Ransom
如果我没记错的话,这只存在于Vista及以后的版本中。最好能在XP上实现,因为很多人仍在使用它。 - dutt
奇怪,他们声称需要Vista,但又声称应该将_WIN32_WINNT定义为0x0500(Windows 2000)或更高版本。看起来矛盾。 - Mark Ransom
马克,那可能只是一个打字错误——应该是6而不是5。 - Rob Kennedy

2
对于Vista及以上版本,有SetCurrentConsoleFontEx,已经说过了。
对于2K和XP,有一个未记录的函数SetConsoleFont;例如在这里阅读。
typedef BOOL (WINAPI *FN_SETCONSOLEFONT)(HANDLE, DWORD);
FN_SETCONSOLEFONT SetConsoleFont;
..........
HMODULE hm = GetModuleHandle(_T("KERNEL32.DLL"));
SetConsoleFont = (FN_SETCONSOLEFONT) GetProcAddress(hm, "SetConsoleFont");
// add error checking
..........

SetConsoleFont(GetStdHandle(STD_OUTPUT_HANDLE), console_font_index);

现在,console_font_index 是控制台字体表中的索引,其定义未知。但是,已知console_font_index == 10标识Lucida Console(Unicode字体)。我不确定此值在不同操作系统版本之间的稳定性。

更新

在dutt的评论后,我在一个干净的XP SP2设置上运行了一个实验。

  • 最初,GetNumberOfConsoleFonts()确实返回10,字体索引0..9指定各种光栅字体。

  • 在我打开具有其属性中选择了Lucida字体的控制台后(仅一次;我可以立即关闭它,但效果相同),突然GetNumberOfConsoleFonts()开始返回12,并且索引10和11选择不同大小的Lucida。

因此,当我玩这个技巧时,它对我起作用是因为我始终至少运行一个选择了Lucida字体的控制台应用程序。

因此,从实际角度考虑,Jon Hanson的回答似乎更好。除了提供更好的控制,它实际上还起作用。 :)

它确实改变了字体,但是GetNumberOfConsoleFonts()对我来说返回的是10,我已经尝试了0-9(以及10,11等),但这些都不是Lucida Console。现在的问题是,我该如何使用它来切换到Lucida控制台? :) - dutt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接