c ++ - Brug af flere skrifttyper i konsol applikation med WinAPI

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg skriver en konsol ansøgning ved hjælp af WinAPI og jeg bemærkede en mærkelig opførsel

af SetCurrentConsoleFontEx funktionen.


Appen bruger to typer skrifttyper:


// 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!
");

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


Efter lanceringen af ​​applikationen ser begge tekstlinier sig ens ud (som font0).

Men hvis jeg tilføjer Sleep(100) mellem printf("This text is big! ")

og SetCurrentConsoleFontEx(outHnd, FALSE, &font0),

programmet vil fungere korrekt (1. tekst er større end 2.).

Det virker også, når jeg bruger forsinkelsessløjfe:


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


Hvorfor sker dette og hvordan man ændrer skrifttyper uden yderligere forsinkelsesfunktioner/sløjfer?

Bedste reference


i den generelle situation næste - i konsolproduktionen var der to processer - din ansøgning ( Klient ) og conhost.exe ( Server ) (oprettet af din proces) fra vista, i xp - din app og + csrss.exe)


Hver konsolfunktion, herunder tekstudgang i din proces, gør fjernsynet (synkron) til conhost.exe (via internt ConsoleCallServer). for at forstå, hvorfor denne adfærd behøver fejlfinding conhost.exe


i den nuværende gennemførelse conhost.exe har 3 tråde:



  1. ConsoleIoThread tråd - det kommunikerer med din konsol
    ansøgning

  2. ConsoleInputThread Dette er brugergrænsefladen til konsollen, spin i
    GetMessage loop

  3. Microsoft::Console::Render::RenderThread::\_ThreadProc - dette
    tråd vente på en begivenhed (lad navnet være m\_hEvent). denne begivenhed indstillet af
    ConsoleIoThread når din app anmoder om en handling, som tekst
    output eller skriftændring. udfør denne handling og start igen vente på
    begivenhed (m\_hEvent)



lad se hvad der sker, når du ringer SetCurrentConsoleFontEx på server side:
ConsoleIoThread (1) vække og gøre det næste:


SrvSetConsoleCurrentFont
  SCREEN\_INFORMATION::UpdateFont(FontInfo*)
    SCREEN\_INFORMATION::RefreshFontWithRender
      Microsoft::Console::Render::Renderer::TriggerFontChange(int, FontInfo*)
        Microsoft::Console::Render::GdiEngine::UpdateFont(FontInfo*)
        SetEvent(m\_hEvent)


kort: Opret/vælg til enhedskontekst ny skrifttype og meddeler gendannelse (3) efter SetEvent(m\_hEvent)


Når du ringer printf på Server side igen ConsoleIoThread (1) vækker og gør det næste:


SrvWriteConsole 
  DoSrvWriteConsole
    WriteCharsLegacy
      Microsoft::Console::Render::Renderer::TriggerRedraw(SMALL\_RECT*)
        Microsoft::Console::Render::GdiEngine::Invalidate(SMALL\_RECT*)
        SetEvent(m\_hEvent)


Efter denne gendannede tråd (3) vågner og gør din tekst med nuværende skrifttype.


Hvad er der, hvis du foretager de næste opkald for hurtigt ?:


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


ConsoleIoThread (1) kalder UpdateFont(FontInfo*) to gange før RenderThread (3) vækker! som resultat andet opkald til UpdateFont(FontInfo*) overskriv første opkald.


men hvis du gør det næste:


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


RenderThread (3) Vågner første gang, når du venter på Sleep og gør gengivelse med font1 og gør så allerede med font0