Reputation: 20780
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.
Upvotes: 23
Views: 38313
Reputation: 42842
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.
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.
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.
Upvotes: 1
Reputation: 1246
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.
Upvotes: 15
Reputation: 11483
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).
Upvotes: 1
Reputation: 34393
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.
Upvotes: 3