Redirecting cerr and clog to OutputDebugString()

std::cout, std::cerr and std::clog are streams just like any other. And just like any other, they work in conjuction with a stringbuf object.

The Win32 OutputDebugString function allows you to send a message to your debugger. In Visual C++ 2010, it is displayed in the “Output” window.

The code below will modify cerr and clog to redirect the data to the debugger.

#include <ostream>
#include <Windows.h>

/// \brief This class is a derivate of basic_stringbuf which will output all the written data using the OutputDebugString function
template<typename TChar, typename TTraits = std::char_traits<TChar>>
class OutputDebugStringBuf : public std::basic_stringbuf<TChar,TTraits> {
public:
	explicit OutputDebugStringBuf() : _buffer(256) {
		setg(nullptr, nullptr, nullptr);
		setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
	}

	~OutputDebugStringBuf() {
	}

	static_assert(std::is_same<TChar,char>::value || std::is_same<TChar,wchar_t>::value, "OutputDebugStringBuf only supports char and wchar_t types");

	int sync() try {
		MessageOutputer<TChar,TTraits>()(pbase(), pptr());
		setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
		return 0;
	} catch(...) {
		return -1;
	}

	int_type overflow(int_type c = TTraits::eof()) {
		auto syncRet = sync();
		if (c != TTraits::eof()) {
			_buffer[0] = c;
			setp(_buffer.data(), _buffer.data() + 1, _buffer.data() + _buffer.size());
		}
		return syncRet == -1 ? TTraits::eof() : 0;
	}


private:
	std::vector<TChar>		_buffer;

	template<typename TChar, typename TTraits>
	struct MessageOutputer;

	template<>
	struct MessageOutputer<char,std::char_traits<char>> {
		template<typename TIterator>
		void operator()(TIterator begin, TIterator end) const {
			std::string s(begin, end);
			OutputDebugStringA(s.c_str());
		}
	};

	template<>
	struct MessageOutputer<wchar_t,std::char_traits<wchar_t>> {
		template<typename TIterator>
		void operator()(TIterator begin, TIterator end) const {
			std::wstring s(begin, end);
			OutputDebugStringW(s.c_str());
		}
	};

};

Usage :

int main() {
	#ifndef NDEBUG
		#ifdef _WIN32
			static Utilities::OutputDebugStringBuf<char> charDebugOutput;
			std::cerr.rdbuf(&charDebugOutput);
			std::clog.rdbuf(&charDebugOutput);
		
			static Utilities::OutputDebugStringBuf<wchar_t> wcharDebugOutput;
			std::wcerr.rdbuf(&wcharDebugOutput);
			std::wclog.rdbuf(&wcharDebugOutput);
		#endif
	#endif

	...

	std::cerr << "Error: something bad happened" << std::endl;		// will be displayed in the debugger

	...
}

111 thoughts on “Redirecting cerr and clog to OutputDebugString()

  1. Thanks for the code!

    I needed to do some things to get it to compile cleanly:
    between lines 1 & 2: added “#include ”
    beginning of line 8: removed “explicit”
    (explicit is only for constructors with 1 argument)
    beginning of line 17: added “protected”
    beginning of lines 18 & 26: added “virtual”
    beginning of line 27: replaced “auto” with “int”
    (auto is default storage type)
    line 29: added “(TChar)” between “=” and “c”
    (eliminate possible truncation warning)

    With those changes, it compiles with no warnings or errors at warning level W4.

    Nice work!

  2. Indeed, nice work!

    The code uses the latest greatest in C++0x and STL.

    I had to make small changes to make it compile under Visual Studio 2008.

    Code is below.

    -88-

    #include
    #include
    #include
    #include
    #include

    #define nullptr NULL

    /// \brief This class is a derivate of basic_stringbuf which will output all the written data using the OutputDebugString function
    template<typename TChar, typename TTraits = std::char_traits>
    class OutputDebugStringBuf : public std::basic_stringbuf {
    public:
    OutputDebugStringBuf() : _buffer(1024) {
    setg(nullptr, nullptr, nullptr);

    //Visual Studio 2010 has data() member in vector class
    // setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0], &_buffer[0] + _buffer.size());
    }

    ~OutputDebugStringBuf() {
    }

    //static_assert(std::is_same::value || std::is_same::value, “OutputDebugStringBuf only supports char and wchar_t types”);

    int sync()
    {
    try {
    MessageOutputer()(pbase(), pptr());
    //Visual Studio 2010 has data() member in vector class
    // setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0], &_buffer[0] + _buffer.size());
    return 0;
    } catch(…) {
    return -1;
    }
    }

    std::char_traits::int_type overflow(std::char_traits::int_type c = TTraits::eof()) {
    int syncRet = sync();
    if (c != TTraits::eof()) {
    _buffer[0] = c;
    // Visual Studio 2010 code
    // setp(_buffer.data(), _buffer.data() + 1, _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0] + 1, &_buffer[0] + _buffer.size());
    }
    return syncRet == -1 ? TTraits::eof() : 0;
    }

    private:
    std::vector _buffer;

    template
    struct MessageOutputer;

    template
    struct MessageOutputer<char,std::char_traits> {
    template
    void operator()(TIterator begin, TIterator end) const {
    std::string s(begin, end);
    OutputDebugStringA(s.c_str());
    }
    };

    template
    struct MessageOutputer<wchar_t,std::char_traits> {
    template
    void operator()(TIterator begin, TIterator end) const {
    std::wstring s(begin, end);
    OutputDebugStringW(s.c_str());
    }
    };
    };

  3. One more try with proper quotes…

    #include <string>
    #include <sstream>
    #include <iostream>
    #include <ostream>
    #include <vector>

    #define nullptr NULL

    /// \brief This class is a derivate of basic_stringbuf which will output all the written data using the OutputDebugString function
    template<typename TChar, typename TTraits = std::char_traits<TChar>>
    class OutputDebugStringBuf : public std::basic_stringbuf<TChar,TTraits> {
    public:
    OutputDebugStringBuf() : _buffer(1024) {
    setg(nullptr, nullptr, nullptr);

    //Visual Studio 2010 has data() member in vector class
    // setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0], &_buffer[0] + _buffer.size());
    }

    ~OutputDebugStringBuf() {
    }

    //static_assert(std::is_same<TChar,char>::value || std::is_same<TChar,wchar_t>::value, “OutputDebugStringBuf only supports char and wchar_t types”);

    int sync()
    {
    try {
    MessageOutputer<TChar,TTraits>()(pbase(), pptr());
    //Visual Studio 2010 has data() member in vector class
    // setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0], &_buffer[0] + _buffer.size());
    return 0;
    } catch(…) {
    return -1;
    }
    }

    std::char_traits<char>::int_type overflow(std::char_traits<char>::int_type c = TTraits::eof()) {
    int syncRet = sync();
    if (c != TTraits::eof()) {
    _buffer[0] = c;
    // Visual Studio 2010 code
    // setp(_buffer.data(), _buffer.data() + 1, _buffer.data() + _buffer.size());

    // Visual Studio 2008 code
    setp(&_buffer[0], &_buffer[0] + 1, &_buffer[0] + _buffer.size());
    }
    return syncRet == -1 ? TTraits::eof() : 0;
    }

    private:
    std::vector<TChar> _buffer;

    template<typename TChar, typename TTraits>
    struct MessageOutputer;

    template<>
    struct MessageOutputer<char,std::char_traits<char>> {
    template<typename TIterator>
    void operator()(TIterator begin, TIterator end) const {
    std::string s(begin, end);
    OutputDebugStringA(s.c_str());
    }
    };

    template<>
    struct MessageOutputer<wchar_t,std::char_traits<wchar_t>> {
    template<typename TIterator>
    void operator()(TIterator begin, TIterator end) const {
    std::wstring s(begin, end);
    OutputDebugStringW(s.c_str());
    }
    };
    };

  4. I have a question.

    In VS2012 I got a warning message of

    1>c:\users\kims11\codes\projects\opengl\sandbox\my_opengl_tests\test05\windows_error_output.h(94): warning : exception specification for virtual function “OutputDebugStringBuf::~OutputDebugStringBuf” is incompatible with that of overridden function “std::basic_streambuf::~basic_streambuf [with _Elem=TChar, _Traits=TTraits]”

    What does this mean? Is it possible to correct this?

    BTW, this is a beautiful piece of codes.
    Thanks a lot.

  5. Pingback: Louis
  6. Pingback: stuart
  7. Pingback: Herman
  8. Pingback: Darrell
  9. Pingback: Henry
  10. Pingback: Keith
  11. Pingback: arturo
  12. Pingback: jon
  13. Pingback: Charles
  14. Pingback: ted
  15. Pingback: Jackie
  16. Pingback: Milton
  17. Pingback: gene
  18. Pingback: Arturo
  19. Pingback: Edgar
  20. Pingback: Mario
  21. Pingback: troy
  22. Pingback: Roy
  23. Pingback: Mitchell
  24. Pingback: shawn
  25. Pingback: Brent
  26. Pingback: arthur
  27. Pingback: steve
  28. Pingback: Andy
  29. Pingback: Jackie
  30. Pingback: Harvey
  31. Pingback: Francisco
  32. Pingback: oscar
  33. Pingback: trevor
  34. Pingback: Neil
  35. Pingback: Gary
  36. Pingback: Nathan
  37. Pingback: Morris
  38. Pingback: tracy
  39. Pingback: Henry
  40. Pingback: Cecil
  41. Pingback: russell
  42. Pingback: ben
  43. Pingback: Troy
  44. Pingback: Kent
  45. Pingback: Randall
  46. Pingback: arturo
  47. Pingback: rex
  48. Pingback: brent
  49. Pingback: Ernest
  50. Pingback: Danny
  51. Pingback: alvin
  52. Pingback: Leslie
  53. Pingback: Johnny
  54. Pingback: nicholas
  55. Pingback: trevor
  56. Pingback: benjamin
  57. Pingback: nathan
  58. Pingback: Christopher
  59. Pingback: ray
  60. Pingback: Jackie
  61. Pingback: wallace
  62. Pingback: keith
  63. Pingback: Brad
  64. Pingback: neil
  65. Pingback: morris
  66. Pingback: Jose
  67. Pingback: jorge
  68. Pingback: nathan
  69. Pingback: Nathaniel
  70. Pingback: Virgil
  71. Pingback: cameron
  72. Pingback: Dustin
  73. Pingback: Joshua
  74. Pingback: jay
  75. Pingback: Douglas
  76. Pingback: charlie
  77. Pingback: Antonio
  78. Pingback: Roberto
  79. Pingback: alberto
  80. Pingback: shawn
  81. Pingback: kirk
  82. Pingback: Clayton
  83. Pingback: dennis
  84. Pingback: Johnny
  85. Pingback: wade
  86. Pingback: ross
  87. Pingback: Stuart
  88. Pingback: eugene
  89. Pingback: Micheal
  90. Pingback: jimmie
  91. Pingback: Marvin
  92. Pingback: gilbert
  93. Pingback: Jimmie
  94. Pingback: Ralph
  95. Pingback: travis
  96. Pingback: Kevin
  97. Pingback: edward
  98. Pingback: franklin
  99. Pingback: don
  100. Pingback: Scott
  101. Pingback: Bruce
  102. Pingback: Greg
  103. Pingback: Vanessa Smith
  104. Pingback: firefox download
  105. Pingback: java download
  106. Pingback: skype download

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>