March 7, 2011 0

Win32 Project with console

By dominic in C/C++

Writing stuff to the console is one of the most basic means of debugging we have when writing a program. Yet, when creating a native C++ windows program, anything you write to one of the IO streams just gets ignored. There is a simple way to use a console in Win32 app, here is how.
The first thing to do is call AllocConsole(), and AttachConsole() passing it the current pid (GetCurrentProcessId()).
All this does is allocate a new console and attaches it to the current application.

1
2
AllocConsole();
AttachConsole(GetCurrentProcessId());

That’s nice, but using std::cout at that point won’t send anything to the console we just created. What we need to do is replace the cin/cout/cerr stream buffers with the console’s buffer:

1
2
3
4
5
6
7
8
// first we need to backup the current stream buffer so that we can restore it later
std::streambuf *backup = std::cout.rdbuf();
 
// then we need to open the output stream associated with the console
std::ofstream console_out("CONOUT$");
 
// once we have the console buffer, we can set it as the std::cout stream buffer
std::cout.rdbuf(console_out.rdbuf());

This works just the same for std::cin and std::cerr.
Now, whatever you send to std::cin/out/err will be printed to the console.
Once you are done with the console you just need to call FreeConsole() to remove it, and remember to restore the original stream buffers associated with the cout/in/err.

1
2
console_out.close();
std::cout.rdbuf(backup);

The best way to use this code is to wrap it up in a class, because as you will have noticed, if we put this in a function the console_out ofstream would fall out of scope when the function returns, and we don’t want to use global variables to store our streams and buffers.
Here is a basic example of such a class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#ifndef __DBGCONSOLE_H__
# define __DBGCONSOLE_H__
 
#include <iostream>
#include <streambuf>
#include <fstream>
 
class DebugConsole
{
public:
	DebugConsole();
	~DebugConsole();
 
	void open();
	void close();
 
private:
	std::streambuf	*_cinbuf;
	std::streambuf	*_coutbuf;
	std::streambuf	*_cerrbuf;
	std::ifstream	_console_cin;
	std::ofstream	_console_cout;
	std::ofstream	_console_cerr;
};
 
#endif // __DBGCONSOLE_H__
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <windows.h>
#include "DebugConsole.h"
 
DebugConsole::DebugConsole() :
	_cinbuf(0), _coutbuf(0), _cerrbuf(0)
{
}
 
DebugConsole::~DebugConsole() {}
 
void DebugConsole::open()
{
	AllocConsole();
	AttachConsole(GetCurrentProcessId());
	this->_cinbuf = std::cin.rdbuf();
	this->_console_cin.open("CONIN$");
	std::cin.rdbuf(this->_console_cin.rdbuf());
	this->_coutbuf = std::cout.rdbuf();
	this->_console_cout.open("CONOUT$");
	std::cout.rdbuf(this->_console_cout.rdbuf());
	this->_cerrbuf = std::cerr.rdbuf();
	this->_console_cerr.open("CONOUT$");
	std::cerr.rdbuf(this->_console_cerr.rdbuf());
}
 
void DebugConsole::close()
{
	this->_console_cout.close();
	std::cout.rdbuf(this->_coutbuf);
	this->_console_cin.close();
	std::cin.rdbuf(this->_cinbuf);
	this->_console_cerr.close();
	std::cerr.rdbuf(this->_cerrbuf);
	FreeConsole();
}

Nothing fancy, but useful.

Tags: ,

Leave a Reply