Posts Color your console output using VB.NET!
Post
Cancel

Color your console output using VB.NET!

By Cory Smith

<FONT color=#ff0000>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.</FONT>

Download source code - 2.28kb

Introduction

Back in the days before Windows (yes, even Windows 3.x) we used to have applications that took advantage of the DOS prompt's ability to change the foreground and background colors to present data in a more meaningful manner.  As we've move foreward 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

<FONT color=#0000ff size=2>

Option

</FONT><FONT color=#0000ff size=2>Explicit</FONT> <FONT color=#0000ff size=2>On
</FONT><FONT color=#0000ff size=2>Option</FONT> <FONT color=#0000ff size=2>Strict</FONT> <FONT color=#0000ff size=2>On
</FONT><FONT color=#0000ff size=2>
Imports</FONT> System.Runtime.InteropServices
<FONT color=#0000ff size=2>Imports</FONT> Win32.Kernel32.ConsoleColor

<FONT color=#0000ff size=2>Namespace</FONT> Win32.Kernel32

<FONT color=#0000ff size=2>  Class</FONT> ConsoleColor

      <FLAGS()></FLAGS()>
<FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Enum</FONT> ForegroundColors
        Black = 0
        Blue = 1
        Green = 2
        Cyan = Blue
<FONT color=#0000ff size=2>Or</FONT> Green
        Red = 4
        Magenta = Blue
<FONT color=#0000ff size=2>Or</FONT> Red
        Yellow = Green
<FONT color=#0000ff size=2>Or</FONT> Red
        White = Blue
<FONT color=#0000ff size=2>Or</FONT> Green <FONT color=#0000ff size=2>Or</FONT> Red
        Gray = 8
        LightBlue = Gray
<FONT color=#0000ff size=2>Or</FONT> Blue
        LightGreen = Gray
<FONT color=#0000ff size=2>Or</FONT> Green
        LightCyan = Gray
<FONT color=#0000ff size=2>Or</FONT> Cyan
        LightRed = Gray
<FONT color=#0000ff size=2>Or</FONT> Red
        LightMagenta = Gray
<FONT color=#0000ff size=2>Or</FONT> Magenta
        LightYellow = Gray
<FONT color=#0000ff size=2>Or</FONT> Yellow
        BrightWhite = Gray
<FONT color=#0000ff size=2>Or</FONT> White
<FONT color=#0000ff size=2>      End</FONT> <FONT color=#0000ff size=2>Enum </FONT>

      <FLAGS()></FLAGS()>

<FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Enum</FONT> BackgroundColors
        Black = 0
        Blue = 16
        Green = 32
        Cyan = Blue
<FONT color=#0000ff size=2>Or</FONT> Green
        Red = 64
        Magenta = Blue
<FONT color=#0000ff size=2>Or</FONT> Red
        Yellow = Green
<FONT color=#0000ff size=2>Or</FONT> Red
        White = Blue
<FONT color=#0000ff size=2>Or</FONT> Green <FONT color=#0000ff size=2>Or</FONT> Red
        Gray = 128
        LightBlue = Gray
<FONT color=#0000ff size=2>Or</FONT> Blue
        LightGreen = Gray
<FONT color=#0000ff size=2>Or</FONT> Green
        LightCyan = Gray
<FONT color=#0000ff size=2>Or</FONT> Cyan
        LightRed = Gray
<FONT color=#0000ff size=2>Or</FONT> Red
        LightMagenta = Gray
<FONT color=#0000ff size=2>Or</FONT> Magenta
        LightYellow = Gray
<FONT color=#0000ff size=2>Or</FONT> Yellow
        BrightWhite = Gray
<FONT color=#0000ff size=2>Or</FONT> White
<FONT color=#0000ff size=2>    End</FONT> <FONT color=#0000ff size=2>Enum

</FONT>    <FLAGS()></FLAGS()><FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Enum</FONT> Attributes
        None = &H0
        GridHorizontal = &H400
        GridLVertical = &H800
        GridRVertical = &H1000
        ReverseVideo = &H4000
        Underscore = &H8000
<FONT color=#0000ff size=2>    End</FONT> <FONT color=#0000ff size=2>Enum
 
   </FONT><FONT color=#0000ff size=2>Private</FONT> <FONT color=#0000ff size=2>Const</FONT> STD_OUTPUT_HANDLE <FONT color=#0000ff size=2>As</FONT> <FONT color=#0000ff size=2>Integer</FONT> = -11
   
<FONT color=#0000ff size=2>Private</FONT> <FONT color=#0000ff size=2>Shared</FONT> InvalidHandleValue <FONT color=#0000ff size=2>As</FONT> <FONT color=#0000ff size=2>New</FONT> IntPtr(-1)
 
   
<FONT color=#0000ff size=2>Private</FONT> <FONT color=#0000ff size=2>Sub</FONT> <FONT color=#0000ff size=2>New</FONT>()
     
<FONT color=#008000 size=2>' This class can not be instantiated.
   </FONT><FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Sub
 
   </FONT><FONT color=#008000 size=2>' Our wrapper implementations.
   </FONT><FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Overloads</FONT> <FONT color=#0000ff size=2>Shared</FONT> <FONT color=#0000ff size=2>Sub</FONT> SetConsoleColor(<FONT color=#0000ff size=2>ByVal</FONT> foreground <FONT color=#0000ff size=2>As</FONT> ForegroundColors)
      SetConsoleColor(foreground, BackgroundColors.Black, Attributes.None)
   
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Sub
 
   </FONT><FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Overloads</FONT> <FONT color=#0000ff size=2>Shared</FONT> <FONT color=#0000ff size=2>Sub</FONT> SetConsoleColor(<FONT color=#0000ff size=2>ByVal</FONT> foreground <FONT color=#0000ff size=2>As</FONT> ForegroundColors, _
                                                                                       
<FONT color=#0000ff size=2>ByVal</FONT> background <FONT color=#0000ff size=2>As</FONT> BackgroundColors)
      SetConsoleColor(foreground, background, Attributes.None)
   
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Sub
 
   </FONT><FONT color=#0000ff size=2>Public</FONT> <FONT color=#0000ff size=2>Overloads</FONT> <FONT color=#0000ff size=2>Shared</FONT> <FONT color=#0000ff size=2>Sub</FONT> SetConsoleColor(<FONT color=#0000ff size=2>ByVal</FONT> foreground <FONT color=#0000ff size=2>As</FONT> ForegroundColors, _
                                                                                        
<FONT color=#0000ff size=2>ByVal</FONT> background <FONT color=#0000ff size=2>As</FONT> BackgroundColors, _
                                                                                       
<FONT color=#0000ff size=2>ByVal</FONT> attribute <FONT color=#0000ff size=2>As</FONT> Attributes)
     
<FONT color=#0000ff size=2>Dim</FONT> handle <FONT color=#0000ff size=2>As</FONT> IntPtr = GetStdHandle(STD_OUTPUT_HANDLE)
     
<FONT color=#0000ff size=2>If</FONT> handle.Equals(InvalidHandleValue) <FONT color=#0000ff size=2>Then
       </FONT><FONT color=#0000ff size=2>Throw</FONT> <FONT color=#0000ff size=2>New</FONT> System.ComponentModel.Win32Exception()
     
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>If
<FONT color=#008000 size=2>      ' We have to convert the integer flag values into a Unsigned Short (UInt16) to pass to the
      ' SetConsoleTextAttribute API call.
</FONT>     </FONT><FONT color=#0000ff size=2>Dim</FONT> value <FONT color=#0000ff size=2>As</FONT> UInt16 = System.Convert.ToUInt16(foreground <FONT color=#0000ff size=2>Or</FONT> background <FONT color=#0000ff size=2>Or</FONT> attribute)
     
<FONT color=#0000ff size=2>If</FONT> <FONT color=#0000ff size=2>Not</FONT> SetConsoleTextAttribute(handle, value) <FONT color=#0000ff size=2>Then
       </FONT><FONT color=#0000ff size=2>Throw</FONT> <FONT color=#0000ff size=2>New</FONT> System.ComponentModel.Win32Exception()
     
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>If
   </FONT><FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Sub</FONT>

<FONT color=#008000 size=2>    ' DLLImport's (Win32 functions)
   </FONT><DLLIMPORT("KERNEL32.DLL", setlasterror:="</font"><FONT color=#0000ff size=2>True)> _
   
<FONT color=#0000ff size=2>Private</FONT> <FONT color=#0000ff size=2>Shared</FONT> <FONT color=#0000ff size=2>Function</FONT> GetStdHandle(<FONT color=#0000ff size=2>ByVal</FONT> stdHandle <FONT color=#0000ff size=2>As</FONT> <FONT color=#0000ff size=2>Integer</FONT>) <FONT color=#0000ff size=2>As</FONT> IntPtr
   
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Function

   </FONT><DLLIMPORT("KERNEL32.DLL", setlasterror:="</font"><FONT color=#0000ff size=2>True)> _
   
<FONT color=#0000ff size=2>Private</FONT> <FONT color=#0000ff size=2>Shared</FONT> <FONT color=#0000ff size=2>Function</FONT> SetConsoleTextAttribute(<FONT color=#0000ff size=2>ByVal</FONT> consoleOutput <FONT color=#0000ff size=2>As</FONT> IntPtr, _
                                                                                             <MARSHALAS(UNMANAGEDTYPE.U2)>_
                                                                                             </MARSHALAS(UNMANAGEDTYPE.U2)>
<FONT color=#0000ff size=2>ByVal</FONT> Attributes <FONT color=#0000ff size=2>As</FONT> UInt16) <FONT color=#0000ff size=2>As</FONT> <FONT color=#0000ff size=2>Boolean
   </FONT><FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Function</FONT>

<FONT color=#0000ff size=2>  End</FONT> <FONT color=#0000ff size=2>Class

End

</FONT><FONT color=#0000ff size=2>Namespace</FONT>

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

<FONT color=#0000ff size=2>

Option

</FONT><FONT color=#0000ff size=2>Explicit</FONT> <FONT color=#0000ff size=2>On
</FONT><FONT color=#0000ff size=2>Option</FONT> <FONT color=#0000ff size=2>Strict</FONT> <FONT color=#0000ff size=2>On
</FONT><FONT color=#0000ff size=2>
</FONT><FONT color=#0000ff size=2>Imports</FONT> Win32.Kernel32.ConsoleColor

<FONT color=#0000ff size=2>Module</FONT> ConsoleColorTest
 
<FONT color=#0000ff size=2>Sub</FONT> Main()

    
<FONT color=#0000ff size=2>Dim</FONT> bgcolor <FONT color=#0000ff size=2>As</FONT> BackgroundColors
   
<FONT color=#0000ff size=2>Dim</FONT> fgcolor <FONT color=#0000ff size=2>As</FONT> ForegroundColors

   
<FONT color=#008000 size=2>' Show every variation of the color combinations.
    </FONT><FONT color=#0000ff size=2>For</FONT> <FONT color=#0000ff size=2>Each</FONT> bgcolor <FONT color=#0000ff size=2>In</FONT> [Enum].GetValues(<FONT color=#0000ff size=2>GetType</FONT>(BackgroundColors))
<FONT color=#0000ff size=2><FONT color=#000000>      </FONT>For</FONT> <FONT color=#0000ff size=2>Each</FONT> fgcolor <FONT color=#0000ff size=2>In</FONT> [Enum].GetValues(<FONT color=#0000ff size=2>GetType</FONT>(ForegroundColors))
        SetConsoleColor(fgcolor, bgcolor)
        Console.WriteLine(bgcolor.ToString.PadRight(15) & fgcolor.ToString.PadRight(64))
     
<FONT color=#0000ff size=2>Next
    </FONT><FONT color=#0000ff size=2>Next

    </FONT><FONT color=#008000 size=2>' Set the color back to the default.
    </FONT>SetConsoleColor(ForegroundColors.White, BackgroundColors.Black)

    
<FONT color=#008000 size=2>' Wait for input, so we can view the results.
    </FONT>Console.ReadLine()
  
<FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Sub
</FONT><FONT color=#0000ff size=2>End</FONT> <FONT color=#0000ff size=2>Module</FONT>

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

SetConsoleTextAttribute (Platform SDK / MSDN)
Writing colored text to the console (C#) by Shawn A. Van Ness
Putting colour/color to work on the console by Philip Fitzsimons (C#)

</DLLIMPORT("KERNEL32.DLL",></FONT></DLLIMPORT("KERNEL32.DLL",></FONT>

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