Post

Color your console output using VB.NET!

By Cory Smith

Note: This sample has been replaced by the ‘Control Your Console’ ConsoleEx sample available from the Samples listing. In addition to being able to specify the color, you can control cursor position, window title, determine size of the console and much more.

Download source code - 2.28kb

picture

Introduction

Back in the days before Windows (yes, even Windows 3.x) we used to have applications that took advantage of the DOS prompts ability to change the foreground and background colors to present data in a more meaningful manner. As we’ve move forward with a Windows interface, developers creating console applications have all but forgotten that they too have this ability. Sure, most of the time, these applications are for testing purposes, but it would still be nice to have the output presented in a manner that allows the user to quickly identify important portions of the data that is being presented. For example, you could have a console application that shows you the output of some task; presenting you with successful, questionable, and failed/error events. Each of these could be marked using green, yellow, and red foreground colors to allow the user to quickly identify one type of event over the others based on color alone.

Now, for the problem. .NET console applications do not give you the ability to modify the foreground and background colors of what you output to the screen. However, since .NET console application are true Windows console applications, we can leverage a few Windows API’s to assist us with this problem.

We we’re going to do is wrap up the necessary API calls into a re-usable component class. We’re going to expand upon the flag values by creating all of the variations of the colors; instead of relying on OR‘ing all of the values to create the various combinations. This will give us more of a .NET feel. In the end, this re-usable component will have three overloaded shared methods that allows us to modify the output colors. We will also mark this class so that we can’t create an instance of the class; only allowing for the shared access methods.

ConsoleColor.vb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
Option Explicit On
Option Strict On

Imports System.Runtime.InteropServices
Imports Win32.Kernel32.ConsoleColor

Namespace Win32.Kernel32

  Class ConsoleColor 

    <Flags()>
    Public Enum ForegroundColors 
      Black = 0 
      Blue = 1 
      Green = 2 
      Cyan = Blue Or Green 
      Red = 4 
      Magenta = Blue Or Red 
      Yellow = Green Or Red 
      White = Blue Or Green Or Red 
      Gray = 8 
      LightBlue = Gray Or Blue 
      LightGreen = Gray Or Green 
      LightCyan = Gray Or Cyan 
      LightRed = Gray Or Red 
      LightMagenta = Gray Or Magenta 
      LightYellow = Gray Or Yellow 
      BrightWhite = Gray Or White 
    End Enum    
  
    <Flags()>
    Public Enum BackgroundColors 
      Black = 0 
      Blue = 16 
      Green = 32 
      Cyan = Blue Or Green 
      Red = 64 
      Magenta = Blue Or Red 
      Yellow = Green Or Red 
      White = Blue Or Green Or Red 
      Gray = 128 
      LightBlue = Gray Or Blue 
      LightGreen = Gray Or Green 
      LightCyan = Gray Or Cyan 
      LightRed = Gray Or Red 
      LightMagenta = Gray Or Magenta 
      LightYellow = Gray Or Yellow 
      BrightWhite = Gray Or White 
    End Enum 

    <Flags()>
    Public Enum Attributes 
      None =  &H0 
      GridHorizontal =  &H400 
      GridLVertical =  &H800 
      GridRVertical =  &H1000 
      ReverseVideo =  &H4000 
      Underscore =  &H8000 
    End Enum 

    Private Const STD_OUTPUT_HANDLE As Integer = -11 
    Private Shared InvalidHandleValue As New IntPtr(-1) 
   
    Private Sub New  () 
    ' This class can not be instantiated. 
    End Sub 
   
    ' Our wrapper implementations. 
    Public Overloads Shared Sub SetConsoleColor(ByVal foreground As ForegroundColors) 
      SetConsoleColor(foreground, BackgroundColors.Black, Attributes.None) 
    End Sub 
   
    Public Overloads Shared Sub SetConsoleColor(ByVal foreground As ForegroundColors, _ 
                                                ByVal background As BackgroundColors) 
      SetConsoleColor(foreground, background, Attributes.None) 
    End Sub 
   
    Public Overloads Shared Sub SetConsoleColor(ByVal foreground As ForegroundColors, _ 
                                                ByVal background As BackgroundColors, _ 
                                                ByVal attribute As Attributes)
      Dim handle As IntPtr = GetStdHandle(STD_OUTPUT_HANDLE) 
      If handle.Equals(InvalidHandleValue) Then 
        Throw New System.ComponentModel.Win32Exception() 
      End If 
      ' We have to convert the integer flag values into a Unsigned Short (UInt16) to pass to the  
      ' SetConsoleTextAttribute API call. 
      Dim value As UInt16 = System.Convert.ToUInt16(foreground Or background Or attribute) 
      If Not SetConsoleTextAttribute(handle, value) Then 
        Throw New System.ComponentModel.Win32Exception() 
      End If 
    End Sub     
    
    ' DLLImport's (Win32 functions) 
    <DLLIMPORT("KERNEL32.DLL", setlasterror:=True )> _ 
    Private Shared Function GetStdHandle(ByVal stdHandle As Integer) As IntPtr 
    End Function 
 
    <DLLIMPORT("KERNEL32.DLL", setlasterror:= True )> _ 
    Private Shared Function SetConsoleTextAttribute(ByVal consoleOutput As IntPtr, _
                                                    <MARSHALAS(UNMANAGEDTYPE.U2)> ByVal Attributes As UInt16) As Boolean 
    End Function     
  End Class
End Namespace    

Now that we have our re-usable class, let’s create a test application to try out our new capabilities we’ve added to the console. NOTE: I’ve added the Attributes portion for completeness; however, it doesn’t appear to work using Windows XP.

ConsoleColorTest.vb

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Option Explicit On 
Option Strict On 
   
Imports Win32.Kernel32.ConsoleColor 
 
Module ConsoleColorTest 

  Sub Main() 
 
    Dim bgcolor As BackgroundColors 
    Dim fgcolor As ForegroundColors 
  
    ' Show every variation of the color combinations. 
    For Each bgcolor In [Enum].GetValues(GetType(BackgroundColors)) 
      For Each fgcolor In [Enum].GetValues(GetType(ForegroundColors)) 
        SetConsoleColor(fgcolor, bgcolor) 
        Console.WriteLine(bgcolor.ToString.PadRight(15) & fgcolor.ToString.PadRight(64)) 
      Next 
    Next 
 
    ' Set the color back to the default. 
    SetConsoleColor(ForegroundColors.White, BackgroundColors.Black) 
 
    ' Wait for input, so we can view the results. 
    Console.ReadLine() 
  
  End Sub 

End Module    

This demo is pretty straight forward. It simply loops through all of the foreground and background values to display every combination of the values. As you can see, it’s now very simple to add the capability to modify the foreground and background color of your console applications output.

I have to point out one of the cool parts of this sample. You can iterate through an enumeration pretty much like any other “collection”. You have to use the Enum.GetValues method to do this. Notice, since Enum is a reserved word in VB, you have to place the square brackets around it.

Conclusion

There is a lot more that you can do with the console output. This includes moving the cursor position, set font size, and change the window title. The code provided will give you a head start on implementing any additional functionality that the Platform SDK offers concerning console applications. As you can see, VB.NET’s not having unsigned values does not hinder us from implementing this functionality. The System.Convert class comes in very handy, as does the MarshalAs attribute for these sticky situations.

UPDATE: If there is any interest, I’ve expanded on this quite a bit. The version that I’m working on allows you to clear the screen, move the cursor around, etc. allowing you work with a command prompt similar to back in the good ol’ QB4.5 days ;-) If enough comments are left, I’ll consider created a part two to this article… so start commenting ;-)

Resources

This post is licensed under CC BY 4.0 by the author.