Console windows and standard streams
Posted September 30th, 2007 by William WillingCategories: Programming
Console windows can be convenient for outputting debug information, but you don’t need them all the time. With the Windows API, you can create and destroy a console window whenever you want, so this gives you the opportunity to only create a console window when your program actually has something to report. However, by default these console windows aren’t connected to the standard streams, so std::cout, std::cerr and std::cin won’t work. Fortunately, it’s not that hard to fix. I spent some time to solve this problem and I thought I’d share my solution.
You can create a console window with a call to AllocConsole() and you can destroy it with FreeConsole(). That’s it. You don’t need to obtain a handle or anything, because we are not going to use the Windows API functions for reading from and writing to the console window. Instead, we’ll redirect the standard streams.
Let’s look at how to redirect std::cout so that it outputs to the console window. First, we need to store the buffer that is currently attached to std::cout, so that we can reset std::cout when we don’t need the console window anymore.
std::streambuf* old_cout = std::cout.rdbuf();
Next, we need to open a stream that point to our console window. We can do this by opening a file called CONOUT$. Windows knows that this isn’t really a file but a console and it will deal with it accordingly. After we have opened the file, we attach the stream to std::cout.
std::ofstream console_out("CONOUT$");
std::cout.rdbuf(console_out.rdbuf());
That’s it. You can now use std::cout to write to your console window. It works the same for std::cerr, except that you use CONERR$ instead of CONOUT$. To redirect std::cin, use CONIN$ and open a std::ifstream instead of a std::ofstream. (I’ll give you the full code in a minute.)
Restoring std::cout to its previous state is simple.
std::cout.rdbuf(old_cout);
One thing you need to be aware of, is that a file stream will be closed once it goes out of scope. If at that time std::cout is still attached to that stream, you can’t write to std::cout anymore or things will go horribly wrong. So, the following code is bad.
void redirect_cout()
{
std::ofstream console_out("CONOUT$");
std::cout.rdbuf(console_out.rdbuf());
} // BAD: console_out goes out of scope here
The easiest way to deal with this problem, is by wrapping the code in a class. The following class implements everything I just discussed: it creates a console window and redirects the standard streams to it on construction, and it restores the standard streams and destroys the console window on destruction. Just create an instance of this class and you’ll have a console window that responds to the standard streams, without having to worry about the clean up.
// console.h
#ifndef __CONSOLE_H__
#define __CONSOLE_H__
#include <fstream>
class console
{
private:
std::ofstream m_out;
std::ofstream m_err;
std::ifstream m_in;
std::streambuf* m_old_cout;
std::streambuf* m_old_cerr;
std::streambuf* m_old_cin;
public:
console();
~console();
};
#endif
// console.cpp
#include "console.h"
#include <cstdio>
#include <iostream>
#include <windows.h>
console::console()
{
// create a console window
AllocConsole();
// redirect std::cout to our console window
m_old_cout = std::cout.rdbuf();
m_out.open("CONOUT$");
std::cout.rdbuf(m_out.rdbuf());
// redirect std::cerr to our console window
m_old_cerr = std::cerr.rdbuf();
m_err.open("CONOUT$");
std::cerr.rdbuf(m_err.rdbuf());
// redirect std::cin to our console window
m_old_cin = std::cin.rdbuf();
m_in.open("CONIN$");
std::cin.rdbuf(m_in.rdbuf());
}
console::~console()
{
// reset the standard streams
std::cin.rdbuf(m_old_cin);
std::cerr.rdbuf(m_old_cerr);
std::cout.rdbuf(m_old_cout);
// remove the console window
FreeConsole();
}
One final note. The above code won’t work for C-streams, so printf() still won’t write anything in the console window. I never use printf() myself, but if you do, you might be interested in redirecting the stdout stream. Here is the code you need.
freopen("CONOUT$", "w", stdout);
Apparently, there is no way to find out where stdout is currently directed, so it’s impossible to restore stdout to its previous state. The best you can do is to reset stdout to its default and hope that no-one has redirected it previously. In most cases, that is acceptable.
freopen("OUT", "w", stdout);
Hopefully, this is helpful to someone.
October 1st, 2007 at 4:38 pm
I remember writing code in VS6 and getting frustrated that I couldn’t output any text unless I ran the program within the IDE. Then a professor gave us some code to get the console working, but I never bothered to learn what made it work.
Now I know…even though consoles “just work” on Gnu/Linux if you run an application from the command line. B-)
October 31st, 2007 at 11:25 pm
Thanks so much for this article! I’ve been trying to figure out how to redirect stdout when using AllocConsole for a Windows Service I’m writing. Your article is clear, to the point, and very helpful.
January 8th, 2008 at 3:03 pm
can you create a game with nothing but Dev-c++?
And if you need something else what is it?
January 8th, 2008 at 8:37 pm
In theory, you can. In practice, you will need a library for handling input and graphics. I suggest having a look at SDL.
January 9th, 2008 at 8:33 am
but my teacher said only the most exprienced can do that and it will take years
January 9th, 2008 at 8:51 pm
Your teacher is right, so you’d better start right away. Dogged determination: it’s all you need, really.
January 10th, 2008 at 8:07 am
Well actually i will be wanting to go into a school that will teach Programming and games design. I would like to know if i would actually be able to create games even without the help of a teacher before going into it because my aim is to be able to create simple games or preferably more difficult games at home by myself. Would I be able to?
January 10th, 2008 at 8:34 pm
As I said, determination is the key. Everything you need to know to create games, you can learn on your own.
January 11th, 2008 at 1:09 pm
ok thanks a lot
January 13th, 2008 at 3:09 pm
what is the difference between flash games and 3D games?
January 13th, 2008 at 9:51 pm
Oh, my. Flash games are games made in Flash. 3D games are games that render the game world in 3D. In general, creating 3D games is really hard. It’s best not to start with 3D games. Flash allows you to create games with only a small amount of programming. That’s a good route to take if your graphical skills are stronger than your programming skills and if your main interest isn’t in programming anyway. Otherwise you’d best pick up a programming language. C++ is common, but not that easy. Python in combination with pygame (http://www.pygame.org/) is a friendlier introduction.
January 15th, 2008 at 4:10 pm
I see. Thanks but it seems i will not fully understand unless I learn : )
January 31st, 2008 at 6:03 am
Could you explain more on the game engine or something like that?
May 22nd, 2008 at 11:53 pm
Thanks - This is PERFECT!
August 14th, 2008 at 1:53 am
Thanks, this was exactly what I needed!
December 3rd, 2008 at 7:58 am
Thank you so much!!! I could not understand why the console was not being created in my win32 project.
Coming from linux, this is really confusing and irritating. But your solution makes perfect sense. Thank you for the clear explanation and the awesome code sample. I integrated it and low-and-behold it worked like a charm
I hope the universe smiles you sharing this