Как перенаправить стандартный вывод в окно вывода из Visual Studio - PullRequest
21 голосов
/ 09 марта 2011

Можно ли перенаправить стандартный вывод в окно вывода из Visual Studio? Я использую в своей программе OutputDebugString, но я использую некоторые библиотеки, которые имеют выходные сообщения отладки с printf или cout.

Ответы [ 4 ]

10 голосов
/ 06 марта 2015

С https://web.archive.org/web/20140825203329/http://blog.tomaka17.com/2011/07/redirecting-cerr-and-clog-to-outputdebugstring/:

#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());
        }
    };
};

Тогда:

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

    ...

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

    ...
}

Возможно, вы захотите использовать его с

IsDebuggerPresent ()

, чтобы он по-прежнему выводился на консоль, когда не запускается из отладчика Visual Studio.

4 голосов
/ 09 марта 2011

Прямое перенаправление стандартного вывода не будет работать, так как отсутствует дескриптор, соответствующий OutputDebugString. Однако должен быть способ:

Это может быть сделано путем перенаправления stdout в канал, а затем создания потока, который будет читать канал и печатать что-либо из него, используя OutputDebugString.

Примечание: я давно задумывался о том, чтобы реализовать это, поскольку сталкиваюсь с точно такой же проблемой, как и вы (некоторые библиотеки, использующие printf или fprintf (stderr ....), однако я никогда этого не делал, я вместо этого я всегда заканчивал модификацию библиотек, поэтому у меня нет работающей реализации, но я думаю, что это должно быть осуществимо в принципе.

3 голосов
/ 09 марта 2011

Да.Я предполагаю, что вы работаете над Win32 GUI-приложением.

Ваша реализация c определяет 3 дескриптора для stdin, stdout и stderr.Win32 определяет эквивалентные дескрипторы, которые определяют, где будет отображаться фактический физический ввод / вывод.c такими функциями, как «printf», используйте эти дескрипторы Win32 для выполнения ввода-вывода.По сути, вам нужно создать консоль для вывода, а затем перенаправить туда, куда указывает стандартный вывод Win32.а затем получить дескриптор к стандартному выводу c и связать его со стандартным выводом Win32.

Эта ссылка содержит дополнительную информацию о том, как это сделать:добавить два новых файла в ваше приложение (ссылка содержит списки).

0 голосов
/ 08 апреля 2015

Я использую Visual Studio 2012, а также хотел перенаправить stdout и stderr при отладке скрипта, программы на C ++ или MSTest DLL без необходимости изменения самого исходного кода,Мой подход, который я наконец-то придумал, состоял в том, чтобы захватить вывод, используя своего рода промежуточную программу.

Создание консольного приложения C # Windows

Возьмите следующий код C # и создайте / скомпилируйте консольное приложение Windows C # .NET:

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);
            }
        }
    }
}

Я использовал Trace.WriteLine ()вместо Debug.WriteLine (), потому что тогда он работает и в версии выпуска вышеуказанного кода.

Использование приложения в отладке проекта VS

ПРИМЕЧАНИЕ: Если у вас естьвыбрал .NET 4 / 4.5 и вы захватываете вывод неуправляемого кода, вам нужно выбрать Mixed в качестве типа отладки / отладчика в настройках проекта.В противном случае (при Авто ) вы можете получить необработанное исключение KernelBase.dll .

Теперь вы можете использовать приложение, поместив вновь созданный

OutputDebugStringConsole.exe

в свойства отладки / команды и

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

или, например, если это MSTest DLL

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

в ваши отладки / аргументы приложения, которое вы хотите отлаживать.Кавычки в аргументах команды необходимы для обработки пробелов в пути вашего приложения.

Пожалуйста, используйте это только в качестве примера, для чего может использоваться приложение.Я знаю, что VS 2012 Test Explorer действительно предлагает очень хороший способ запуска MSTest DLL и получения выходных данных в структурированном виде.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...