Search code examples
c#cvb.netconsoleansi-escape

VB.NET Console: Use ANSI Sequences (Console Virtual Terminal Sequences)


I am trying to write a console app in VB.NET (VS Studio Community 2019 & .Net framework 4.8) I cannot get it to display ANSI Escape sequences correctly. I am aware of this suggestion and have applied it. (Makes no difference)

I am able to set colour using

Console.ResetColor()
Console.ForegroundColor = ConsoleColor.Red

and cursor positioning, using

Console.SetCursorPosition(origCol + x, origRow + y)
Console.Write(s)

When I try to do this

Console.WriteLine("\u001b[31mHello World!\u001b[0m")

It just prints it out raw without interpreting the ANSI Sequences.

Console.OutputEncoding = Text.Encoding.XXX only gives me limited options for XXX, including Ascii, UTF8, 16, 32 and Unicode.

I have gone over This article on "Console Virtual Terminal Sequences", which seems to be Microsoft's term for ANSI Codes. This article refers to setConsoleMode.

There is also this snippet of C, for which I can find no equivalent in vb.net

// Set output mode to handle virtual terminal sequences
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    if (hOut == INVALID_HANDLE_VALUE)
    {
        return GetLastError();
    }

    DWORD dwMode = 0;
    if (!GetConsoleMode(hOut, &dwMode))
    {
        return GetLastError();
    }

    dwMode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
    if (!SetConsoleMode(hOut, dwMode))
    {
        return GetLastError();
    }

I'm guessing that one of these two might be the answer to my problem, but I have no idea how to do anything with this info in VB.net.


Solution

  • The question title indicates the programming is VB.net. Yet this statement is shown

    Console.WriteLine("\u001b[31mHello World!\u001b[0m")
    

    in which the C# style unicode escape sequence, \u001b is used. VB does not support escape sequences. A proper VB statement using string interpolation and the ChrW Function would be:

    Console.WriteLine($"{ChrW(&H1B)}[31mHello World!{ChrW(&H1B)}[0m")
    

    There is also this snippet of C, for which I can find no equivalent in vb.net

    This will require using the Platform Invoke (PInvoke) feature to call the native api functions. A direct conversion of the snippet is wrapped in the SetVT100Mode method defined below. You can find the various constants in either the documentation or by looking at the examples at Pinvoke.net.

    Imports System.Runtime.InteropServices
    
    Module Module1
      Private Const STD_INPUT_HANDLE As Int32 = -10
      Private Const STD_OUTPUT_HANDLE As Int32 = -11
      Private Const STD_ERROR_HANDLE As Int32 = -12
      Private ReadOnly INVALID_HANDLE_VALUE As New IntPtr(-1)
      Private Const ENABLE_VIRTUAL_TERMINAL_PROCESSING As UInt32 = &H4
    
      Sub Main()
        Const Esc As Char = ChrW(27)
    
        If SetVT100Mode() = 0 Then
          Console.WriteLine($"{Esc}[31mHello World!{Esc}[0m")
        End If
    
        Console.ReadLine()
    
      End Sub
    
      Private Function SetVT100Mode() As Int32
        Dim hOut As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)
        If hOut = INVALID_HANDLE_VALUE Then
          Return Marshal.GetLastWin32Error()
        End If
    
        Dim mode As UInt32
        If Not GetConsoleMode(hOut, mode) Then
          Return Marshal.GetLastWin32Error()
        End If
    
        mode = mode Or ENABLE_VIRTUAL_TERMINAL_PROCESSING
        If Not SetConsoleMode(hOut, mode) Then
          Return Marshal.GetLastWin32Error()
        End If
        Return 0
      End Function
    
      <DllImport("kernel32.dll", SetLastError:=True)>
      Private Function GetConsoleMode(ByVal hConsoleHandle As IntPtr, ByRef lpMode As UInteger) As Boolean
      End Function
    
      <DllImport("kernel32.dll", SetLastError:=True)>
      Private Function SetConsoleMode(ByVal hConsoleHandle As IntPtr, ByVal dwMode As UInteger) As Boolean
      End Function
    
      <DllImport("kernel32.dll", SetLastError:=True)>
      Private Function GetStdHandle(ByVal nStdHandle As Integer) As IntPtr
      End Function
    
    End Module