[Note to readers of comp.lang.c++.moderated:
I'm posting this here as it may be useful to other C++ programmers
on the Win32 platform. For those who don't use Win32,
::OutputDebugString sends a C-style string to the "debug output
stream", which is monitored by debugging utilities. Conceptually,
its like std::clog, but is accessible from languages besides C++
as it is a provision of the Win32 API, not just C++.
On Win32, the prototypes are:
void ::OutputDebugStringA(const char *);
void ::OutputDebugStringW(const wchar_t *);
OutputDebugString is conditionally defined to be either the A or
W form token, depending on whether the build is ANSI or UNICODE.]
Do you use the C++ standard string and stringstream classes to build
debug information which you dump with OutputDebugString?
I do this all the time, but I was getting sick of the
OutputDebugString repitition. At first I was providing an overloaded
function that did the str() and c_str() business:
void
ODS(const std::basic_ostringstream<TCHAR> &buff)
{
::OutputDebugString(buff.str().c_str());
}
void
ODS(const std::basic_string<TCHAR> &str)
{
::OutputDebugString(buff.c_str());
}
(Note: std::string is just a typedef for std::basic_string<char>;
similarly std::wstring is a typedef for std::basic_string<wchar_t>.
TCHAR is defined as either char or wchar_t, so
std::basic_string<TCHAR> is the same as std::string in ANSI builds
and the same as std::wstring in UNICODE builds.
std::basic_ostringstream<> is handled similarly.)
But this was still tedious because you had to build up the string to
be dumped in a stringstream buffer and then call ODS() on the
buffer, so you end up writing code like this all the time:
{
std::basic_ostringstream<TCHAR> buff;
buff << _T("M = ") << m << std::endl;
ODS(buff);
}
What would really be handy would be a stream like std::cout that was
wired up to OutputDebugString. So getting out my copy of "Standard C++
IOStreams and Locales" by Langer and Kreft, I wrote a std::streambuf
class that you can hook to a stream (any ostream, really) and then use
it like std::cout, std::cerr or std::clog. A .h file declares the
global output stream, and a .cpp file implements the streambuf and
instantiates the global instance. Now you can just write:
g_ods << _T("M = ") << m << std::endl;
and the output will magically appear on the output debug stream.
No more calls to ::OutputDebugString(), the ODS() overloaded function
hack, or declaring local stringstreams just to construct the string.
Use std::endl instead of _T("\n") to ensure that the internal buffer
is flushed, forcing the debug output to show right away. Otherwise,
the output is dumped via OutputDebugString when:
- the internal buffer overflows
- the std::flush manipulator is used
- g_ods.flush() is called
or
- the stream is destroyed
Since the stream is a global object, it won't be destroyed until after
the main routine exits, which is quite late in the lifetime of the
program :-).
When dumping the output from the internal buffer, care is taken to
preserve the line-oriented nature of the data, in case other chunks
of code (like D3D or D3DX) are dumping output to the debug stream.
You can force partial lines to print on the debug stream by flushing
g_ods.
Sprinkle a few overloaded operator<<'s around and you've got yourself
the ability to dump out lots of debugging information easily. Plus,
if you want to dump it to a file, you can do that simply by
changing the one line in ods.cpp that defines g_ods and recompiling
that one file. You won't need to recompile any of the code that
dumps the debug information, nor do you need to change any of the
string dumping code to make it go to a file instead of the output
debug stream.
The implementation of g_ods can be found in at
<http://www.xmission.com/~legalize/book/snippets/ods.zip>; include
the .h in anything that wants to write to g_ods and add the .cpp to
your project to provide the definition of g_ods.
You may find tstring.h a useful addition to ods.zip for writing your
own operator<<'s for streams of TCHARs.
<http://www.xmission.com/~legalize/book/snippets/rt/tstring.h>
The code has been tested on an ANSI build, but it is intended to be
ANSI/UNICODE ignorant and should work fine on UNICODE. However,
there may be a minor 'gotcha' under UNICODE since its not been
tested in that situation. If you encounter a problem, please let me
know and I'll supply a fix.
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book <http://www.xmission.com/~legalize/book/>
izfree: Open source tools for Windows Installer
<http://izfree.sourceforge.net>
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
[ about comp.lang.c++.moderated. First time posters: do this! ]
Mmmm... I think it will be nicer if the streambuf flushes itself when
receiving a '\n'.
Regards.
NotFound <bla...@hobbiton.org> spake the secret code
<3CA13286...@hobbiton.org> thusly:
>> Use std::endl instead of _T("\n") to ensure that the internal buffer
>> is flushed, forcing the debug output to show right away. Otherwise,
>> the output is dumped via OutputDebugString when:
>
>Mmmm... I think it will be nicer if the streambuf flushes itself when
>receiving a '\n'.
No, you don't want to do that because newline and flushing are not
the same thing. Its the same reasoning that '\n' doesn't flush
cout.
If you want flushing with every newline, then use std::endl, those
are exactly its semantics.
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
>> Use std::endl instead of _T("\n") to ensure that the internal buffer
>> is flushed, forcing the debug output to show right away. Otherwise,
>> the output is dumped via OutputDebugString when:
>
> Mmmm... I think it will be nicer if the streambuf flushes itself when
> receiving a '\n'.
>
I would go further, and flush the buffer after every write (ie, forgo the
buffering and just implement the put methods with OutputDebugString. )
Nothing is worse than a debug message that is still in the buffer when the
program crashes ;)
Cheers,
Ian McCulloch
But doing normal output and doing debug info logging are not the same
things. I don't see any reason to not flush the buffer on newline in the
second.
Regards.
Wouldn't it be better to make it unit-buffered, to make sure as much
information as possible is flushed? I used a very similar facility,
and usually when debugging, it made sense to have it unit-buffered,
because otherwise, when a crash occurs or a breakpoint is reached, you
don't always have and endl around, so some information remains
unflushed. Btw, cerr is unit-buffered, for the same reason, I believe.
-Vahan
Ian McCulloch <ian.mc...@wanadoo.nl> spake the secret code
<a7tgdg$ve2$2...@scavenger.euro.net> thusly:
>I would go further, and flush the buffer after every write (ie, forgo the
>buffering and just implement the put methods with OutputDebugString. )
If you do that, you find that your debug output is interspersed
mid-line with debug output from other DLLs in the system.
But hey, I provided you with the source, you can make it do whatever
you want.
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
NotFound <bla...@hobbiton.org> spake the secret code
<3CA18957...@hobbiton.org> thusly:
>But doing normal output and doing debug info logging are not the same
>things. I don't see any reason to not flush the buffer on newline in the
>second.
The debug stream is just another output stream.
Like I said, if you want flushing on every newline, use std::endl,
that's exactly what it does!
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
mar...@yahoo.com (Vahan Margaryan) spake the secret code
<44d2ad1a.02032...@posting.google.com> thusly:
>Wouldn't it be better to make it unit-buffered, to make sure as much
>information as possible is flushed?
I don't know what you mean by "unit-buffered", I've never heard that
term before.
If you mean call ::OutputDebugString for every character, then no, I
don't think that is better because you aren't the only one sending
strings to the debug stream -- as I said in my original post D3D,
D3DX, and any arbitrary DLL or third-party library may output strings
to the debug stream. If you flush the stream on every character then
you can get debug output like this:
The vaD3DX: (INFO) Using SSE Instructions
lue of x is 5.
Not to mention the fact that calling ::OutputDebugString for -every-
character is probably going to slow down your app noticeably.
But like I've said already -- I'm giving you the source, if you don't
like it go write your own streambuf from scratch or based on the code
I've made available.
The code I wrote pushes out complete lines from the buffer every 16
characters, at the minimum. Because I don't "own" the debug output
stream in the sense that any code can send messages to it, I don't
want partial lines output like the above unless I explicitly flush a
partial line.
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I agree. I was supposing that every piece of info writed is on a
separate line, but of course is an assumption not neccesarily valid.
Regards.
Rich,
In the May 1999 issue of C++ Report, Kenneth Brubaker published an
article named "DebugIo Library: Formatting Debug Output Using the
Standard C++ Library," where he makes use of OutputDebugString. The
utility wraps the differences between char and wchar_t . You end up
with the following:
tdprintf - A printf-like function that sends to OutputDebugString.
TDPRINTF - A macro for tdprintf that makes it available only on debug
builds.
tdout - A stream that sends to OutputDebugString
TDOUT - A macro for tdout that makes it available only on debug
builds.
The output is done character by character. It can easily be modified
for buffered output, as mentioned in the other posts.
He states in his article that it does not work with Windows 95 for
some unknown reason. Back then, his email address was
ken.br...@arialsystems.com. I copied the code from the magazine
into VC6 a long time ago--jeez, almost three years--and I've been
using it regularly.
Enjoy,
Javier.
Code follows:
DebugIo.h
------------------------------------------
#if !defined(DEBUGIO_H)
#define DEBUGIO_H
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
/* I couldn't make this work in VC6
#ifdef _DEBUG
#pragma comment(lib, "DebugIoD.lib")
#else
#pragma comment(lib, "DebugIo.lib")
#endif
*/
#include <streambuf>
#include <iomanip>
#include <ostream>
#include <cstdio>
#include <cassert>
#include <string>
using namespace std;
#ifndef ASSERT
#ifdef _DEBUG
#define ASSERT(b) do {assert(b); } while(false)
#else
#define ASSERT(b) (void(0))
#endif
#endif
int dprintf(const char* cszFormat, ...);
int wdprintf(const wchar_t* cwszFormat, ...);
#ifdef _UNICODE
#define tdprintf wdprintf
#else
#define tdprintf dprintf
#endif
#ifdef _DEBUG
#define DPRINTF dprintf
#define WDPRINTF wdprintf
#define TDPRINTF tdprintf
#else
#define DPRINTF 1 ? (void)0 : dprintf
#define WDPRINTF 1 ? (void)0 : wdprintf
#define TDPRINTF 1 ? (void)0 : tdprintf
#endif
// Debug buffer
template<class _E, class _Tr = char_traits<_E> >
class basic_debugbuf : public std::basic_streambuf<_E, _Tr>
{
public:
virtual ~basic_debugbuf() {}
protected:
virtual int_type overflow(int_type c = _Tr::eof());
private:
enum EPlatform
{
s_cePlatformWin32s,
s_cePlatformWinXx,
s_cePlatformWinNt
};
EPlatform GetPlatform();
};
//template<class _E, class _Tr = char_traits<_E> >
template<class _E, class _Tr>
inline basic_debugbuf<_E, _Tr>::int_type
basic_debugbuf<_E, _Tr>::overflow(int_type c)
{
static const EPlatform _s_cePlatform = GetPlatform();
// conversion from 'int' to 'const char' possible loss of data
#pragma warning(disable:4244)
const _E cArg[2] = {c,0};
#pragma warning(default:4244)
if( 1 == sizeof(_E))
{
::OutputDebugStringA(reinterpret_cast<const char*>(cArg));
}
else if (2 == sizeof(_E))
{
if (s_cePlatformWinNt == _s_cePlatform)
{
::OutputDebugStringW(reinterpret_cast<const wchar_t*>(cArg));
}
else
{
char szArg[6] = {0};
::WideCharToMultiByte(CP_ACP, 0,
reinterpret_cast<const wchar_t*>(cArg),
-1, szArg, sizeof szArg, 0 , 0);
::OutputDebugStringA(szArg);
}
}
return c;
}
//template<class _E, class _Tr = char_traits<_E> >
template<class _E, class _Tr>
inline basic_debugbuf<_E, _Tr>::EPlatform
basic_debugbuf<_E, _Tr>::GetPlatform()
{
EPlatform ePlatform = s_cePlatformWin32s;
OSVERSIONINFO osVersionInfo;
osVersionInfo.dwOSVersionInfoSize = sizeof OSVERSIONINFO;
::GetVersionEx(&osVersionInfo);
switch(osVersionInfo.dwPlatformId)
{
case VER_PLATFORM_WIN32s:
ePlatform = s_cePlatformWin32s;
break;
case VER_PLATFORM_WIN32_WINDOWS:
ePlatform = s_cePlatformWinXx;
break;
case VER_PLATFORM_WIN32_NT:
ePlatform = s_cePlatformWinNt;
}
return ePlatform;
}
// Output debug stream
template<class _E, class _Tr = char_traits<_E> >
class basic_odstream : public std::basic_ostream<_E, _Tr>
{
public:
typedef basic_odstream<_E, _Tr> _Myt;
typedef basic_debugbuf<_E, _Tr> _Mydb;
basic_odstream():std::basic_ostream<_E, _Tr>(&_Fb) {}
virtual ~basic_odstream() {}
_Mydb* rdbuf() const { return ((_Mydb*)&_Fb); }
private:
_Mydb _Fb;
};
// Clean up expression or manipulator
class _CNullOut
{
typedef _CNullOut _Myt;
typedef std::basic_ostream<char, std::char_traits<char> >
_Mybos;
typedef std::basic_ios<char, std::char_traits<char> > _Myios;
public:
_Myt& operator<< (_Myt&(_cdecl*)(_Myt&)) { return *this;}
_Myt& operator<< (_Mybos&(_cdecl*)(_Mybos&)) { return *this;}
_Myt& operator<< (_Myios&(_cdecl*)(_Myios&)) { return *this;}
_Myt& operator<< (std::ios_base&(_cdecl*)(std::ios_base&)) {
return *this;}
};
template<typename T> inline
_CNullOut& _cdecl operator<< (_CNullOut& _O, T&)
{
return (_O);
}
template<class _E> inline
_CNullOut& _cdecl operator<< (_CNullOut& _O, const std::_Fillobj<_E>&)
{
return (_O);
}
template<class _Tm> inline
_CNullOut& _cdecl operator<< (_CNullOut& _O, const std::_Smanip<_Tm>&)
{
return (_O);
}
extern basic_odstream<char> dout;
extern basic_odstream<wchar_t> wdout;
#ifdef _UNICODE
#define tdout wdout
#else
#define tdout dout
#endif
#ifdef _DEBUG
#define DOUT dout
#define WDOUT wdout
#define TDOUT tdout
#else
#define DOUT _CNullOut()
#define WDOUT _CNullOut()
#define TDOUT _CNullOut()
#endif
#endif // !defined(DEBUGIO_H)
DebugIo.cpp
--------------------------------
#include <windows.h>
#include "DebugIo.h"
#include <io.h>
#include <fcntl.h>
#include <share.h>
#include <cstdio>
#include <cstdarg>
#include <cassert>
using namespace std;
int dprintf(const char* cszFormat, ...)
{
va_list args;
va_start(args, cszFormat);
FILE* pNullDevice = fopen("\\\\.\\NUL","w");
int nCharCount = vfprintf(pNullDevice, cszFormat, args);
if (0 > nCharCount)
return 0;
std::string strOutput(nCharCount,' ');
int nTrueCharCount = vsprintf(&strOutput[0], cszFormat, args);
if (nTrueCharCount > nCharCount)
{
fclose(pNullDevice);
va_end(args);
assert(false);
// THROW EXCEPTION
return 0;
}
::OutputDebugStringA(strOutput.c_str());
fclose(pNullDevice);
va_end(args);
return nTrueCharCount;
}
int wdprintf(const wchar_t* cwszFormat, ...)
{
va_list args;
va_start(args, cwszFormat);
FILE* pNullDevice = fopen("\\\\.\\NUL","w");
int nCharCount = vfwprintf(pNullDevice, cwszFormat, args);
if (0 > nCharCount)
return 0;
std::wstring wstrOutput(nCharCount,L'');
int nTrueCharCount = vswprintf(&wstrOutput[0], cwszFormat, args);
if (nTrueCharCount > nCharCount)
{
fclose(pNullDevice);
va_end(args);
assert(false);
// THROW EXCEPTION
return 0;
}
::OutputDebugStringW(wstrOutput.c_str());
fclose(pNullDevice);
va_end(args);
return nTrueCharCount;
}
basic_odstream<char> dout;
basic_odstream<wchar_t> wdout;
DebugIoTest.cpp
----------------------------------
#include <windows.h>
#include <iostream>
#include "DebugIo.h"
using namespace std;
void main()
{
tdout << "Hello, world" << endl;
tdout << "Hello, world" << endl;
TDOUT << "Hello, world" << endl;
TDPRINTF("This is a cool utility! %s\n", "Hello??");
ljes...@hotmail.com (Javier Estrada) spake the secret code
<d522680b.02032...@posting.google.com> thusly:
>tdprintf - A printf-like function that sends to OutputDebugString.
>TDPRINTF - A macro for tdprintf that makes it available only on debug
>builds.
<gak> Haven't we had enough printf-style bugs for one lifetime? The
whole point of making a streambuf class was to avoid printf.
>tdout - A stream that sends to OutputDebugString
I prefer my solution which handles the char/wchar_t issue through
the template -- just like the iostreams design intended. He is doing
comparisons to sizeof(char_type) to find out if you're using it as a
narrow or wide stream!
>The output is done character by character.
Like a billion times in this thread, I've already stated why I don't
want to call ::ODS character by character.
>He states in his article that it does not work with Windows 95 for
>some unknown reason.
Probably because wide-character strings are not supported on Win9x
and he's letting you do that.
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
I apologize for not explaining the point completely. A
'unit-buffered'stream is a stream which has the ios_base::unitbuf flag
set. For such streams, flush() is called automatically after every
insertion (all << operators call flush). I intended to suggest that
the unitbuf flag be set when initializing the global g_ods object.
> If you mean call ::OutputDebugString for every character, then no, I
> don't think that is better because you aren't the only one sending
> strings to the debug stream -- as I said in my original post D3D,
> D3DX, and any arbitrary DLL or third-party library may output strings
> to the debug stream. If you flush the stream on every character then
> you can get debug output like this:
>
> The vaD3DX: (INFO) Using SSE Instructions
> lue of x is 5.
>
> Not to mention the fact that calling ::OutputDebugString for -every-
> character is probably going to slow down your app noticeably.
I agree that flush()ing on every character is wrong. I see
unit-buffering as an acceptable compromise (especially since iostreams
kindly support that functionality :). Since flush() is called at the
end of an insertion operator, a meaningful chunk of data (a number or
a string) is flushed, so there's less chance of meaningless output
than when using per-char flush().
-Vahan
I can also look for another tool ;)
Regards.
mar...@yahoo.com (Vahan Margaryan) spake the secret code
<44d2ad1a.02033...@posting.google.com> thusly:
>I apologize for not explaining the point completely. A
>'unit-buffered'stream is a stream which has the ios_base::unitbuf flag
>set. For such streams, flush() is called automatically after every
>insertion (all << operators call flush). I intended to suggest that
>the unitbuf flag be set when initializing the global g_ods object.
Ah, I see now. In that case, the streambuf doesn't have to do
anything, right?
--
Ask me about my upcoming book on Direct3D from Addison-Wesley!
Direct3D Book http://www.xmission.com/~legalize/book/
izfree: Open source tools for Windows Installer
http://izfree.sourceforge.net
[ Send an empty e-mail to c++-...@netlab.cs.rpi.edu for info ]
Right. The streambuf isn't affected in any way. You choose the
flushing mode at the ostream level, you can turn unit-buffering on and
off.
-Vahan