Quetzalcoatl
Quetzalcoatl

Reputation: 3067

Visual Studio 2012 - Embedded output console instead of cmd?

Is it possible to have an embedded output console as part of the VS2012 window instead of opening cmd upon running?

For example, in Eclipse output is directed to the "Console" pane by default, and I would like to achieve something similar in VS2012, if it is available.

Upvotes: 2

Views: 773

Answers (2)

user1522973
user1522973

Reputation:

It's a good idea to create debug output functions that you can then modify as required to redirect output where it needs to go. Keep in mind though that text boxes in Windows are very, very slow compared to the console, and even the console isn't that fast.

If you have a lot of debug output it will have a noticeable effect on your application. For example I was doing some comms with an embedded device and spitting out the raw data to the debug window. It took about 4 minutes to extract the data I needed. I switched the debug output to a real console window and it took about 20 seconds.

These days I just open a real console window using AllocConsole().

Upvotes: 0

Marius
Marius

Reputation: 2273

Here is a complete example of the code involved to do this:

http://blog.tomaka17.com/2011/07/redirecting-cerr-and-clog-to-outputdebugstring/

Basically the author creates a new std::basic_stringbuf that uses the MSVC function OutputDebugString() and binds it to clog and cerr via std::cerr.rdbuf(&newStreamBuf). This should also work for cout.

I actually compiled his code and had some issues with it, here is the corrected version:

cpp file:

// redirectStreamBuf.cpp

//Feel free to modify target options here (for example #ifndef NDEBUG)
#ifdef _WIN32
    #define ENABLE_MSVC_OUTPUT
#endif


#include <iostream>
#include <vector>
#include <sstream>

#ifdef ENABLE_MSVC_OUTPUT
#include <Windows.h>
#endif


#ifdef ENABLE_MSVC_OUTPUT
template<typename TChar, typename TTraits = std::char_traits<TChar>>
class OutputDebugStringBuf : public std::basic_stringbuf<TChar,TTraits> {
public:
    typedef std::basic_stringbuf<TChar, TTraits> BaseClass;

    explicit OutputDebugStringBuf() : _buffer(256) {
        setg(nullptr, nullptr, nullptr);
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
    }

    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() override try {
        MessageOutputer<TChar,TTraits>()(pbase(), pptr());
        setp(_buffer.data(), _buffer.data(), _buffer.data() + _buffer.size());
        return 0;
    } catch(...) {
        return -1;
    }

    typename BaseClass::int_type overflow(typename BaseClass::int_type c = TTraits::eof()) override {
        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());
        }
    };
};
#endif


void RedirectStdoutToMSVC()
{
#ifdef ENABLE_MSVC_OUTPUT
    static OutputDebugStringBuf<char> outputDebugBufChar;
    static OutputDebugStringBuf<wchar_t> outputDebugBufWChar;

    std::cout.rdbuf(&outputDebugBufChar);
    std::cerr.rdbuf(&outputDebugBufChar);
    std::clog.rdbuf(&outputDebugBufChar);

    std::wcout.rdbuf(&outputDebugBufWChar);
    std::wcerr.rdbuf(&outputDebugBufWChar);
    std::wclog.rdbuf(&outputDebugBufWChar);
#endif
}

Header file:

// redirectStreamBuf.h
#ifndef REDIRECT_STREAM_BUF_H__
#define REDIRECT_STREAM_BUF_H__
void RedirectStdoutToMSVC();
#endif

And here is the usage along with some test cases:

#include "redirectStreamBuf.h"
#include <iostream>


int main(char *argv, int argc)
{
    RedirectStdoutToMSVC();

    std::cout << "Test cout" << std::endl;
    std::cerr << "Test cerr" << std::endl;
    std::clog << "Test clog" << std::endl;
    std::wcout << L"Test wcout" << std::endl;
    std::wcerr << L"Test wcerr" << std::endl;
    std::wclog << L"Test wclog" << std::endl;

    printf("This will not work :( \n");

    system("PAUSE"); //Yes I know...
    return 0;
}

I tested all this with Visual Studio 2012 and it works fine. C-Style functions like printf do not work though...

Upvotes: 5

Related Questions