Icon Ressource

[C/C++/WinAPI] ANSI Escapesequenzen in der Windows 10 Console 2020-07-11

Warum?

Die neue Windows Console unterstützt beginnend mit Windows 10.0.10586 ANSI Escapesequenzen im Virtual Terminal Modus, beispielsweise um Text farbig auszugeben. Siehe:
Consoleanwendungen müssen die Console aber zunächst konditionieren um diese Escapesequenzen auch nutzen zu können.
Ziele dieser kleinen Lib sind:
  • Auskapseln der erforderlichen Windows API aus dem Benutzercode.
  • Konditionierung der Windows Console für den VT Modus, bzw. dessen Deaktivierung.
  • Identifikation der Standardstreams die im VT Modus verwendbar sind, um verhindern zu können, Escapesequenzen auszugeben, die nicht gerendert werden und stattdessen in ihrer Textrepräsentation verarbeitet werden.



Wie?

Zwei Dinge sind zu berücksichtigen, die völlig unabhängig voneinander existieren.
  1. Das Consolefenster besitzt einen Eingabe- und einen Ausgabepuffer. Für beide kann der VT Modus im Hostprozess konfiguriert werden, sofern die Anwendung mit einem Consolefenster verknüpft ist und es sich um das neue Windows 10 V2 Consolefenster handelt (conhost.exe ohne angegliederten cscss.exe Runtime Prozess). Ob diese Konfiguration möglich oder nicht möglich ist, gibt letztlich darüber Aufschluss und ist eines der Entscheidungskriterien ob mit Escapesequenzen gearbeitet werden kann. Die SetVTConMode Funktion ist zu diesem Zweck implementiert.
  2. Wenn das Consolefenster konfiguriert werden konnte, bedeutet das noch nicht, dass die Standardeingabe, Standardausgabe und Standardfehlerausgabe auch mit diesem verknüpft sind. Die entsprechenden Handles können durchaus auf eine Datei oder eine Pipe umgeleitet sein, wo Escapesequenzen nicht gerendert werden können. Der Rückgabewert der GetStdReferCon Funktion beinhaltet Informationen, ob das StdIn auf ConIn, und ob StdOut und StdErr auf ConOut verweisen.
Für Parameter und Rückgabewerte dieser Funktionen sind Flags in Form von Macros definiert, mit denen mit Hilfe der üblichen bitweisen Operationen zu arbeiten ist.

Detaillierte Beschreibungen finden sich im win10vt.h Header im Download.



Der folgende Testcode zeigt beispielhaft, wie mit der Lib zu arbeiten ist ("win10vt.h" und "win10vt.c" sind in das Projekt eingebunden und finden sich im Download.):
enable_ansi_esc.c:
#include <stdio.h>
#include "win10vt.h"

int main(void)
{
  // Figure out which of the standard handles refer to the console window (rather than to a file or a pipe).
  unsigned con_connected = GetStdReferCon();
  // Try to enable VT processing for the handles of the attached console window, and retrieve for which it happened to work.
  unsigned vt_enabled = SetVTConMode(VT_CONALL, VT_CONALL);

  if ((vt_enabled & VT_CONOUT) && (con_connected & VT_STDOUT)) // VT sequences can be used for stdout.
  {
    fputs(ESC([42m) "Hello Narrow World!\n" ESC([0m), stdout);
    fputws(ESCW([42m) L"Hello Wide World!\n" ESCW([0m), stdout);
  }
  else // VT sequences not supported for stdout.
  {
    fputs("Hello Narrow World!\n", stdout);
    fputws(L"Hello Wide World!\n", stdout);
  }

  if ((vt_enabled & VT_CONOUT) && (con_connected & VT_STDERR)) // VT sequences can be used for stderr.
    fputs(ESC([41m) "Hello Wrong World!\n" ESC([0m), stderr);
  else // VT sequences not supported for stderr.
    fputs("Hello Wrong World!\n", stderr);

  // Disable VT processing for the handles of the attached console window to be sure subsequent tests are not influenced.
  SetVTConMode(VT_CONALL, VT_CONNONE);

  return 0;
}
Statt den C Ausgabefunktionen, könnten hier auch die C++ Ausgabestreams std::cout, std::wcout und std::cerr oder die entsprechenden Windows API Funktionen wie WriteFile zum Einsatz kommen, um die Effekte zu testen. Das Resultat bliebe gleich.


Dieses Batch Script ruft die kompilierte "enable_ansi_esc.exe" unter unterschiedlichen Konditionen auf. Hier soll gezeigt werden, dass der obige C Code tatsächlich in der Lage war zu erkennen, wo VT Processing möglich ist und wo nicht:
test.bat:
@echo off &setlocal

echo(
echo(*** directly
enable_ansi_esc

echo(
echo(*** pipe (err merged)
enable_ansi_esc 2>&1 | find /v ""

echo(
echo(*** pipe
enable_ansi_esc | find /v ""

echo(
echo(*** for (err merged)
for /f "delims=" %%i in ('2^>^&1 enable_ansi_esc') do echo %%i

echo(
echo(*** for
for /f "delims=" %%i in ('enable_ansi_esc') do echo %%i

echo(
echo(*** redirect to con (err merged)
>con 2>&1 enable_ansi_esc

echo(
echo(*** redirect to con
>con enable_ansi_esc

echo(
pause

Ausgabe:
1594481673684.png


Die Ausgabe ist wie folgt zu interpretieren:
  • Wo VT Processing möglich war, erfolgt die Ausgabe farbig (grün bzw. rot). Standardfarben weiß auf schwarz dort, wo VT Prozessing nicht möglich ist.
  • Bei einer fehlerhaften Entscheidung im Programmcode würde bei den weiß auf schwarz Ausgaben der Escapecode als Text ausgegeben werden, was aber nicht der Fall ist.

  • Like
Reaktionen: Mat
Autor
german
Downloads
93
Aufrufe
1.055
Erstellt am
Letzte Bearbeitung
Bewertung
0,00 Stern(e) 0 Bewertung(en)

Weitere Ressourcen von german

Oben Unten