Background
There are many different schools of how to debug a program (yeah, I know -
write it correctly from the start), but whatever tools you prefer it is often
very convenient just to use the printf approach. Well, since you
are a modern C++ kind of person, you don't really want printf, you
want to use an output stream, like cerr.
There's just one problem though, you are writing Windows applications, so
there is no standard error output to write to. Not true, actually there is, and
you've probably used many times already. When you use one of the TRACE
macros, the result ends up in the Debug pane of Visual Studio. MFC goes through
great pains to turn off all this debug output in Release builds, but it can
often be very convenient to keep it.
Of course, you won't see any output in Visual Studio from a release build,
but there are other programs that can capture this output.
A good one is
DebugView
from www.sysinternals.com.
Incidentially, if you start this program you'll probably see like a million
messages from Internet Explorer. There you go, even Microsoft practise Release
build debugging!
The problem
So, how to direct a standard output stream to the debug terminal? In general, the correct
answer is to derive from streambuf and connect the new class to a
normal ostream. In this way all stream inserters and
manipulators work as expected. In this case we can save some work by deriving from
stringbuf instead. So, without further ado, here's how to do it:
The code
First we include the needed headers.
#include <Windows.h>
#include <ostream>
#include <sstream>
#include <string>
Now for the real work: Since we are using a stringbuf
we only need to override the sync function.
The sync method is what actually transfers the text in the put
area to whatever output destination the streambuf uses, in this
case by calling the API function OutputDebugString.
template <class CharT, class TraitsT = std::char_traits<CharT> >
class basic_debugbuf :
public std::basic_stringbuf<CharT, TraitsT>
{
public:
virtual ~basic_debugbuf()
{
sync();
}
protected:
int sync()
{
output_debug_string(str().c_str());
str(std::basic_string<CharT>());
return 0;
}
void output_debug_string(const CharT *text) {}
};
Next, I specialize the output routine so it calls the Ansi or Unicode API as
appropriate.
template<>
void basic_debugbuf<char>::output_debug_string(const char *text)
{
::OutputDebugStringA(text);
}
template<>
void basic_debugbuf<wchar_t>::output_debug_string(const wchar_t *text)
{
::OutputDebugStringW(text);
}
That's really all you need, but as a convenience I also provide a class
derived from basic_ostream that connects the output stream to the basic_debugbuf
just created.
In order to work just like cout, you should then create a global
object of type dostream or wdostream and use that to
output to.
template<class CharT, class TraitsT = std::char_traits<CharT> >
class basic_dostream :
public std::basic_ostream<CharT, TraitsT>
{
public:
basic_dostream() : std::basic_ostream<CharT, TraitsT>
(new basic_debugbuf<CharT, TraitsT>()) {}
~basic_dostream()
{
delete rdbuf();
}
};
typedef basic_dostream<char> dostream;
typedef basic_dostream<wchar_t> wdostream;
History
- 18-apr-2001 - Original version
- 23-nov-2001 - Updated to use a
stringbuf as suggested by Jim Barry.
Also fixed the remaining HTML markup errors that made the code un-compileable