Windows Console
The Windows console is a fairly simple way to display text — but with a bit of know-how, you can easily tap into it to produce ASCII-art graphics and use it to read keyboard or mouse input.
ASCII Madness used the Windows console to display the effects.
Creating our Window
If you create a standard Win32 console project and run it, it will flash up a console window then close automatically. You can set a breakpoint on the closing brace to stop the program from closing. Run it again, and you'll see that it's not a great window — just the default size. You'll likely also notice that there is a scrollbar on the right hand size. This is because the size of the text buffer for the console can be much larger than the actual size of the console window. We don't really want this — we want to create a window that is a fixed size that we decide on, and to have a buffer that is the same size.
For the purposes of this tutorial, I will use 80 columns and 50 rows of characters, as this is a fairly decent size.
When you create the window, we need to grab two handles from it. A handle is a variable that references part of the console (such as the input and output) and is used with the various function calls that deal with consoles to tell it which console to deal with. We need two handles — a handle to write to the console (sending text and other controlling information to it), which we'll call wHnd — and a handle to read from the console (handling keyboard and mouse events, for example), which we'll call rHnd. The type of wHnd and rHnd is HANDLE, which is defined in Windows.h. We can set up these two variables correctly using the function GetStdHandle(...) (from ),using the constants STD_OUTPUT_HANDLE and STD_INPUT_HANDLE to point it at the right handles for writing to and reading from. The code for this so far is quite simply:
#include <stdlib.h> #include <Windows.h> #include <Tchar.h> HANDLE wHnd; // Handle to write to the console. HANDLE rHnd; // Handle to read from the console. int _tmain(int argc, _TCHAR* argv[]) { // Set up the handles for reading/writing: wHnd = GetStdHandle(STD_OUTPUT_HANDLE); rHnd = GetStdHandle(STD_INPUT_HANDLE); }
It's still not very exciting, though, is it? However, now we have access to the console via its handles, we can control it!
One of the simplest things to change on our console window is the text in the title bar. We don't even have to pass a console handle to it! Simply add the line SetConsoleTitle(TEXT("My shiny new title bar!")); to your program after setting the handles.
However, our window is still the wrong size. Fortunately, the SetConsoleWindowInfo(...) function can come to our aid. It takes three arguments:
- The write handle to console window;
- A boolean flag to say whether we are setting an absolute size or a relative one based on the current size;
- A pointer to a SMALL_RECT that contains the new size information.
A SMALL_RECT is made up of four short integers which correspond to the left, top, right and bottom coordinates of a rectangle. As we're setting up our console window freshly, we'll want to use the absolute values. As we'll be using a 80x50 window, we want our coordinates to range from (0,0) to (79,49). When building the SMALL_RECT to pass to the function you can manually set the .Left, .Top, .Right and .Bottom coordinates manually, or can just use the {.Left, .Top, .Right, .Bottom} syntax as illustrated in the example below:
#include <stdlib.h> #include <Windows.h> #include <Tchar.h> HANDLE wHnd; // Handle to write to the console. HANDLE rHnd; // Handle to read from the console. int _tmain(int argc, _TCHAR* argv[]) { // Set up the handles for reading/writing: wHnd = GetStdHandle(STD_OUTPUT_HANDLE); rHnd = GetStdHandle(STD_INPUT_HANDLE); // Change the window title: SetConsoleTitle(TEXT("Win32 Console Control Demo")); // Set up the required window size: SMALL_RECT windowSize = {0, 0, 79, 49}; // Change the console window size: SetConsoleWindowInfo(wHnd, TRUE, &windowSize); }
Well, that's all very well and good, but if you run it you'll notice one glaring problem — even though our console is the right size now (right click the title bar and click "Properties" to verify this) you'll notice that it's still got that scroll bar and is not 50 lines tall internally (by default it may be 300). We need to fix that!
There is another function to get with grips now — SetConsoleScreenBufferSize(...). This accepts two parameters, this time:
- The console write handle.
- A COORD which specifies the size of the buffer.
A COORD is made up of two short integers, X and Y. In this case, X is the width of the console buffer and Y is the height of the console buffer. As with the SMALL_RECT, we can set the values of the COORD using {X, Y} style notation. To set the buffer size for our console app, add the lines:
// Create a COORD to hold the buffer size: COORD bufferSize = {80, 50}; // Change the internal buffer size: SetConsoleScreenBufferSize(wHnd, bufferSize);
Run the program and — huzzah — it seems to have been set up properly and is the correct size!