Console windows and standard streams

Posted September 30th, 2007 by William Willing

Categories: 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.

16 comments on “Console windows and standard streams”

  1. GBGames Says:

    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-)

  2. JenC Says:

    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.

  3. Electrokinesis Says:

    can you create a game with nothing but Dev-c++?
    And if you need something else what is it?

  4. William Willing Says:

    In theory, you can. In practice, you will need a library for handling input and graphics. I suggest having a look at SDL.

  5. electrokinesis Says:

    but my teacher said only the most exprienced can do that and it will take years

  6. William Willing Says:

    Your teacher is right, so you’d better start right away. Dogged determination: it’s all you need, really. :-)

  7. electrokinesis Says:

    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?

  8. William Willing Says:

    As I said, determination is the key. Everything you need to know to create games, you can learn on your own.

  9. electrokinesis Says:

    ok thanks a lot

  10. electrokinesis Says:

    what is the difference between flash games and 3D games?

  11. William Willing Says:

    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.

  12. electrokinesis Says:

    I see. Thanks but it seems i will not fully understand unless I learn : )

  13. ELectrokinesis Says:

    Could you explain more on the game engine or something like that?

  14. Tego Says:

    Thanks - This is PERFECT!

  15. Alex Says:

    Thanks, this was exactly what I needed!

  16. Kiaran Says:

    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 ;)

RSS feed for comments on this post.

Bad Behavior has blocked 243 access attempts in the last 7 days.