gpt4 book ai didi

c++ - 使用 WinAPI 在控制台应用程序中使用多种字体类型

转载 作者:行者123 更新时间:2023-11-28 01:54:12 25 4
gpt4 key购买 nike

我正在使用 WinAPI 编写控制台应用程序,我注意到 SetCurrentConsoleFontEx 函数有一个奇怪的行为。

该应用使用两种字体:

// small font
CONSOLE_FONT_INFOEX font0;
font0.cbSize = sizeof(CONSOLE_FONT_INFOEX);
font0.nFont = 0;
font0.dwFontSize = { 8, 16 };
font0.FontFamily = FF_DONTCARE;
font0.FontWeight = FW_NORMAL;
wcscpy_s(font0.FaceName, L"Consolas");

// large font
CONSOLE_FONT_INFOEX font1;
font1.cbSize = sizeof(CONSOLE_FONT_INFOEX);
font1.nFont = 1;
font1.dwFontSize = { 16, 32 };
font1.FontFamily = FF_DONTCARE;
font1.FontWeight = FW_BOLD;
wcscpy_s(font1.FaceName, L"Consolas");

SetCurrentConsoleFontEx(outHnd, FALSE, &font1)
printf("This text is big!\n");

SetCurrentConsoleFontEx(outHnd, FALSE, &font0);
printf("This text is small!\n");

启动应用程序后,两个文本行看起来相同(如 font0)。但是如果我在 printf("This text is big!\n")SetCurrentConsoleFontEx(outHnd, FALSE, &font0) 之间添加 Sleep(100) >,程序将正常工作(第一个文本大于第二个)。当我使用延迟循环时它也有效:

int i = 0;
while (i < 100000000)
i++;

为什么会发生这种情况以及如何在没有额外延迟函数/循环的情况下更改字体?

最佳答案

一般情况下 - 在控制台输出中涉及两个进程 - 您的应用程序(客户端)和 conhost.exe(服务器)(已创建通过你的过程)(这是从 vista 开始,在 xp - 你的应用程序和 + csrss.exe)

每个控制台函数,包括进程中的文本输出,都会对 conhost.exe 进行远程(同步)调用(通过内部 ConsoleCallServer)。为了理解为什么这种行为需要调试 conhost.exe

在当前实现中 conhost.exe 有 3 个线程:

  1. ConsoleIoTThread 线程 - 它与您的控制台通信应用
  2. ConsoleInputThread 这是控制台的 UI 线程,旋入GetMessage 循环
  3. Microsoft::Console::Render::RenderThread::_ThreadProc - 这个线程等待某个事件(将其命名为 m_hEvent)。此事件由ConsoleIoTThread 当您的应用请求某些操作时,例如文本输出或字体更改。执行此操作并重新开始等待事件(m_hEvent)

让我们看看当您在服务器端调用 SetCurrentConsoleFontEx 时会发生什么:ConsoleIoTThread (1) 唤醒并进行下一步:

SrvSetConsoleCurrentFont
SCREEN_INFORMATION::UpdateFont(FontInfo*)
SCREEN_INFORMATION::RefreshFontWithRender
Microsoft::Console::Render::Renderer::TriggerFontChange(int, FontInfo*)
Microsoft::Console::Render::GdiEngine::UpdateFont(FontInfo*)
SetEvent(m_hEvent)

简要说明:创建/选择设备上下文新字体并通过 SetEvent(m_hEvent) 通知渲染线程 (3)

当你在服务器端再次调用 printf ConsoleIoTThread (1) 唤醒并执行下一步:

SrvWriteConsole 
DoSrvWriteConsole
WriteCharsLegacy
Microsoft::Console::Render::Renderer::TriggerRedraw(SMALL_RECT*)
Microsoft::Console::Render::GdiEngine::Invalidate(SMALL_RECT*)
SetEvent(m_hEvent)

在此渲染线程 (3) 被唤醒并使用当前字体渲染您的文本后。

如果您执行下一个调用太快会怎样?:

SetCurrentConsoleFontEx(outHnd, FALSE, &font1)
printf("This text is big!\n");
SetCurrentConsoleFontEx(outHnd, FALSE, &font0);
printf("This text is small!\n");

ConsoleIoTThread (1) 调用UpdateFont(FontInfo*) 两次 RenderThread (3) 是觉醒!结果第二次调用 UpdateFont(FontInfo*) 覆盖第一次调用。

但是如果你接下来这样做:

SetCurrentConsoleFontEx(outHnd, FALSE, &font1)
printf("This text is big!\n");
Sleep(1000);// or any unknown delay
SetCurrentConsoleFontEx(outHnd, FALSE, &font0);
printf("This text is small!\n");

RenderThread (3) 在您等待时第一次被唤醒 Sleep 并使用font1 进行渲染并且然后已经使用 font0

渲染

关于c++ - 使用 WinAPI 在控制台应用程序中使用多种字体类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41811782/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com