22

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211
  • 1
    possible duplicate: http://stackoverflow.com/questions/73286/capturing-cout-in-visual-studio-2005-output-window – wimh Mar 09 '11 at 22:15
  • Possible duplicate of [Capturing cout in Visual Studio 2005 output window?](https://stackoverflow.com/questions/73286/capturing-cout-in-visual-studio-2005-output-window) – mr NAE Feb 01 '19 at 07:59

4 Answers4

13

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ozirus
  • 1,216
  • 13
  • 13
  • Works well after you apply a few changes as mentioned in the comments on linked site. (VS2012: add all necessary includes) – St0fF Mar 09 '15 at 11:29
  • Oh, I'm deeply sorry, I can only remember there were some bad includes, and some other compile errors that were pretty easy to fix. – St0fF Nov 25 '15 at 22:04
  • 1
    @Goz: Some comments still available on the Wayback Machine (https://web.archive.org/web/20140825203329/http://blog.tomaka17.com/2011/07/redirecting-cerr-and-clog-to-outputdebugstring/). Copy-pasted here: 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) – Ozirus Nov 26 '15 at 09:08
  • @Ozirus: Nice one. Always forget to check archive.org :) – Goz Nov 26 '15 at 11:58
  • Add `#include ` in the main file – Oneiros Jun 15 '17 at 10:42
  • Please update your answer. It's really unacceptable to knowingly leave broken code as an answer. Links are insufficient. – Rebs Jun 25 '18 at 10:53
3

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Suma
  • 33,181
  • 16
  • 123
  • 191
  • but I've done this... I have redirected stdout to an console using the code from the link I've posted. – BeeBand Mar 09 '11 at 21:09
  • Yes, that is doable and usefull, this question is about a different functionality: OutputDebugString (which is what is directed to the Output/Debug window in the Visual Studio) is not related to a console at all, it is a completely different thing. – Suma Mar 10 '11 at 08:06
  • I hacked this together: http://stackoverflow.com/a/36115332/524504 <- forwarding stdout to OutputDebugString. – masterxilo Mar 20 '16 at 21:46
1

I was using Visual Studio 2012 and also wanted to redirect standard output and standard error while debugging a script, a C++ program or a MSTest DLL without having to change the source code itself. My approach, that I finally came up with, was to capture the output using sort of an intermediate program.

Create C# Windows Console Application

Take the following C# code and create/compile a Windows C# .NET Console Application:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;

namespace OutputDebugStringConsole
{
    class OutputDebugStringConsole
    {
        private static void OutputHandler(object sendingProcess, DataReceivedEventArgs outLine)
        {
            if (null != outLine.Data)
            {
                Trace.WriteLine(outLine.Data);
                Trace.Flush();
                Console.WriteLine(outLine.Data);
            }
        }

        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                return;
            }

            try
            {
                Process p = new Process();

                p.StartInfo.FileName = args[0];
                p.StartInfo.Arguments = String.Join(" ", args, 1, args.Length - 1);
                Trace.WriteLine("Calling " + p.StartInfo.FileName + " " + p.StartInfo.Arguments);
                p.StartInfo.WorkingDirectory = Directory.GetCurrentDirectory();
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.OutputDataReceived += new DataReceivedEventHandler(OutputHandler);
                p.ErrorDataReceived += new DataReceivedEventHandler(OutputHandler);
                p.Start();
                p.BeginOutputReadLine();
                p.BeginErrorReadLine();
                p.WaitForExit();
                // Call WaitForExit() AFTER I know the process has already exited by a successful return from WaitForExit(timeout).
                // This causes the code that reads all remaining pending async data to be executed.
                // see https://groups.google.com/d/msg/microsoft.public.dotnet.framework.sdk/jEen9Hin9hY/FQtEhjdKLmoJ
                Thread.Sleep(100);
                p.WaitForExit();
                p.Close();
            }
            catch (Exception e)
            {
                Trace.WriteLine(e.ToString());
                Console.WriteLine("{0} Exception caught.", e);
            }
        }
    }
}

I used Trace.WriteLine() instead of Debug.WriteLine(), because it then works also in the release version of the above code.

Use Application in Visual Studio Project Debugging

NOTE: If you have chosen .NET 4/4.5 and you are capturing the output of unmanaged code, you need to select Mixed as your Debugging/Debugger Type in your Project Settings. Otherwise (with Auto) you may get an unhandled KernelBase.dll exception.

Now you can use the application by putting the newly created

OutputDebugStringConsole.exe

into Debugging/Command properties and

"$(TargetPath)" [ARGS ...]

or e.g. if it is the MSTest DLL file:

"$(DevEnvDir)CommonExtensions\Microsoft\TestWindow\vstest.console.exe" /Platform:x86 $(TargetPath)

into your Debugging/Arguments of the application you want to debug. The quotation marks in the command arguments are necessary to handle spaces in your application's path.

Please take this only as an example what the application can be used for. I'm aware that the Visual Studio 2012 Test Explorer does offer a very nice way to run MSTest DLL files and get the output in a structured way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Florian
  • 39,996
  • 9
  • 133
  • 149
1

Yes. I'm assuming that you're working on a Win32 GUI application.

Your C implementation defines three handles for standard input, standard output, and standard error. Win32 defines equivalent handles, which define where the actual physical input/output will appear. C functions, such as 'printf', use these Win32 handles to perform I/O. Basically, you have to create a console for output, and then redirect where the Win32 standard output points to. And then getting the handle to the C standard output and associating this with the Win32 standard output.

This link contains more information on how to do this:

You'll need to add two new files to your application (the link contains the listings).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
BeeBand
  • 10,953
  • 19
  • 61
  • 83
  • I don't think that this is enough. What you would like to do is set a HANDLE from OutputDebugString to the stdout. But you cannot obtain a HANDLE to the OutputDebugString. This is some sort of shared memory structure. You would need to create a own handle or pipe and attach the input side to the stdout and the output side to a own implementation that reroutes everything to OutputDebugString. – mkaes Mar 09 '11 at 17:17
  • @mkaes, have you read the code listing in that link I posted? A console is allocated, the Win32 handle for stdout is associated with this console. And the c stdout handle is then associated with the win32 handle. I guess that OutputDebugString() uses the Win32 stdout handle and the point is that OP has to redirect this Win32 stdout to a console that he/she needs to create. ('AllocConsole();') – BeeBand Mar 09 '11 at 17:34