Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect standard output to output window from Visual Studio

Tags:

Is it possible to redirect standard output to the output window from Visual Studio?

I use OutputDebugString in my program, but I use some libraries that have output debug messages with printf's or cout's.

like image 844
Mircea Ispas Avatar asked Mar 09 '11 16:03

Mircea Ispas


2 Answers

From Redirecting cerr and clog to OutputDebugString():

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

/// \brief This class is derives from 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());
        }
    };
};

Then:

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

            static OutputDebugStringBuf<wchar_t> wcharDebugOutput;
            std::wcerr.rdbuf(&wcharDebugOutput);
            std::wclog.rdbuf(&wcharDebugOutput);
        #endif
    #endif

    ...

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

    ...
}

You might want to use it with

IsDebuggerPresent()

so that it still outputs to console when not run from the Visual Studio debugger.

like image 164
Ozirus Avatar answered Oct 06 '22 10:10

Ozirus


Straightforward standard output redirection will not work, as there is no handle corresponding to OutputDebugString. However, there should be a way:

It could be done by redirecting standard output to a pipe, and then creating a thread which would read the pipe and print anything read from it using OutputDebugString.

Note: I was contemplating for a long ago to implement this, as I am facing exactly the same problem as you do (some libraries using printf or fprintf(stderr....). However, I never really did this. I have always ended modifying the libraries instead, and therefore I do not have a working implementation, but I think it should be feasible in principle.

like image 22
Suma Avatar answered Oct 06 '22 10:10

Suma