Introduction


The Console Application is a handy way to write simple utility programs that do not require much in the way of a user interface.  Typically a Console Application uses a command-line interface where the user types commands into the window, presses enter, and the window reports back lines of text with the result of the command execution.

But before there were programs with windows and buttons and fancy widgets to click, there were programs with menus and key-maps and GUIs made of ASCII characters.  You may even have seen such a screen recently when installing an operating system or configuring a BIOS.  There may still be times today when it makes sense to create a modern application that uses a simple interface designed in ASCII which runs in a command prompt window.

Unfortunately for anyone wanting to create such a program, the default Windows console window wrapper used by .Net for Console Applications hides some of the features of the console and exposes the window tailored for command line based input.  If you want to explicitly design a console screen character-by-character, you can do so by setting the cursor position, but when you write to the window at the end of a line the cursor automatically wraps to the next line.  If this occurs at the bottom of the screen, the content will automatically scroll up.  This can cause havoc with your drawing and it may be a bit tricky to figure out how to change this behavior if you have to scour the net looking for an answer.

Problem Example


To demonstrate the issues caused by the default console window behavior, we will attempt to draw a border of asterisk characters around the inside of a console window.  To try this example in VB.Net, simply create a new Console Application and paste in the following code:

Module Module1
 
    Sub Main()
        For x As Integer = 0 To Console.WindowWidth - 1
            Console.SetCursorPosition(x, 0)
            Console.Write("*")
            Console.SetCursorPosition(x, Console.WindowHeight - 1)
            Console.Write("*")
        Next
        For y As Integer = 1 To Console.WindowHeight - 2
            Console.SetCursorPosition(0, y)
            Console.Write("*")
            Console.SetCursorPosition(Console.WindowWidth - 1, y)
            Console.Write("*")
        Next
        Console.ReadKey()
    End Sub
 
End Module

And here is what we get when we run this simple program:



As you can see, the window has automatically scrolled down one line so the top of the border is off-screen.  In this case the scroll bar is visible so the user could scroll back up, but why should they have to, and what happens if the console buffer is the same size as the window?

Windows API to the Rescue


Luckily for us there are two easy-to-use Win32 API methods that we can import into our program and use to change the behavior of the console window:  GetStdHandle and SetConsoleMode, both found in Kernel32.DLL.

With a call to GetStdHandle we will be able to obtain a handle to the console window's output buffer.  This handle can then be used with SetConsoleMode to turn off the automatic line wrap when text is written to the window.

To use these unmanaged methods in our program, we will add a new class called NativeMethods to the project and then declare the external functions:

Friend NotInheritable Class NativeMethods
    Friend Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As IntPtr) As IntPtr
    Friend Declare Function SetConsoleMode Lib "kernel32" (ByVal hConsoleHandle As IntPtr, ByVal dwMode As IntPtr) As IntPtr
 
    Protected Sub New()
    End Sub
End Class

With this sealed-class in place, we can then add one line of code to the beginning of our program to turn off the line wrapping:

NativeMethods.SetConsoleMode(NativeMethods.GetStdHandle(-11), 1)

This calls the SetConsoleMode method passing the result of a call to GetStdHandle passed -11 (the flag value for the output buffer) and a mode value of 1 indicating that controls keys should be processed (such as backspace) but line wrapping should be disabled.  You can see the documentation for the methods to get more information about the parameter values.

Now when we run the program we see the border displayed properly:


Summary


By utilizing two simple unmanaged Win32 functions we can change the default behavior of the console window, making it much easier to do custom character-by-character drawing.

If you are interested in taking the idea of drawing window frames with ASCII text further, you may also be interested in reading How to Draw a Border of ASCII Text in a Console Application.

Appendix A:  Complete Code Sample



Module Module1
    Sub Main()
        NativeMethods.SetConsoleMode(NativeMethods.GetStdHandle(-11), 1)
        Console.BufferWidth = Console.WindowWidth
        Console.BufferHeight = Console.WindowHeight
        For x As Integer = 0 To Console.WindowWidth - 1
            Console.SetCursorPosition(x, 0)
            Console.Write("*")
            Console.SetCursorPosition(x, Console.WindowHeight - 1)
            Console.Write("*")
        Next
        For y As Integer = 1 To Console.WindowHeight - 2
            Console.SetCursorPosition(0, y)
            Console.Write("*")
            Console.SetCursorPosition(Console.WindowWidth - 1, y)
            Console.Write("*")
        Next
        Console.ReadKey()
    End Sub
End Module
 
Friend NotInheritable Class NativeMethods
    Friend Declare Function GetStdHandle Lib "kernel32" (ByVal nStdHandle As IntPtr) As IntPtr
    Friend Declare Function SetConsoleMode Lib "kernel32" (ByVal hConsoleHandle As IntPtr, ByVal dwMode As IntPtr) As IntPtr
 
    Protected Sub New()
    End Sub
End Class