web-dev-qa-db-fra.com

Comment rediriger stdout vers la fenêtre de sortie de visual studio

Est-il possible de rediriger stdout vers la fenêtre de sortie à partir de Visual Studio? J'utilise dans mon programme OutputDebugString mais j'utilise certaines bibliothèques qui ont des messages de débogage en sortie avec printf ou cout.

21
Felics

La redirection directe de stdout ne fonctionnera pas car il n'y a pas de descripteur correspondant à OutputDebugString. Cependant, il devrait y avoir un moyen:

Cela pourrait être fait en redirigeant la sortie standard vers un canal, puis en créant un thread qui lirait le canal et imprimerait tout ce qui y serait lu à l'aide de OutputDebugString.

Remarque: Je réfléchissais depuis longtemps à la mise en œuvre car je suis confronté exactement au même problème que vous (certaines bibliothèques utilisent printf ou fprintf (stderr ....), mais je ne l'ai jamais vraiment fait, j'ai toujours terminé modifier les bibliothèques au lieu de cela, donc je n'ai pas une implémentation fonctionnelle, mais je pense que cela devrait être faisable en principe.

4
Suma

De https://web.archive.org/web/20140825203329/http://blog.tomaka17.com/2011/07/redirecting-cerr-and-clog-tocoutputdebugstring/ :

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

Ensuite:

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

    ...
}

Vous voudrez peut-être l'utiliser avec 

IsDebuggerPresent ()

afin qu'il soit toujours affiché sur la console lorsqu'il n'est pas exécuté à partir du débogueur Visual Studio.

10
Ozirus

Oui. Je suppose que vous travaillez sur une application graphique Win32.

Votre implémentation c définit 3 poignées pour stdin, stdout et stderr. Win32 définit des descripteurs équivalents, qui définissent l'emplacement de l'entrée/sortie physique réelle. C fonctions telles que 'printf', utilisent ces poignées Win32 pour effectuer des E/S. Fondamentalement, vous devez créer une console pour la sortie, puis rediriger où le stdout Win32 pointe. puis attribuez le handle à la sortie standard c et associez-le à la sortie standard Win32.

Ce lien contient plus d’informations sur la procédure à suivre:

Vous devrez ajouter deux nouveaux fichiers à votre application (le lien contient les listes).

3
BeeBand

J'utilise Visual Studio 2012 et je voulais également rediriger stdout et stderr lors du débogage d'un script, d'un programme C++ ou d'un MSTest DLL sans avoir à modifier le le code source lui-même. L’approche que j’ai finalement trouvée consistait à capturer la sortie en utilisant une sorte de programme intermédiaire. 

Créer une application console Windows C #

Prenez le code C # suivant et créez/compilez une application console 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);
            }
        }
    }
}

J'ai utilisé Trace.WriteLine () à la place de Debug.WriteLine () car cela fonctionne également dans la version du code ci-dessus.

Utiliser une application dans le débogage de projet VS

REMARQUE: Si vous avez choisi .NET 4/4.5 et que vous capturez la sortie du code non managé, vous devez sélectionner Mixed comme type de débogage/débogueur dans les paramètres de votre projet. Sinon (avec Auto ), vous pouvez obtenir une exception KernelBase.dll non gérée

Maintenant, vous pouvez utiliser l'application en mettant le nouveau 

OutputDebugStringConsole.exe

dans les propriétés de débogage/commande et 

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

ou par exemple si c'est la DLL MSTest

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

dans votre débogage/arguments de l’application que vous souhaitez déboguer. Les guillemets dans les arguments de commande sont nécessaires pour gérer les espaces dans le chemin d'accès de votre application.

Veuillez prendre ceci uniquement comme exemple d'utilisation de l'application. Je suis conscient que VS 2012 Test Explorer offre un moyen très agréable d'exécuter des DLL MSTest et d'obtenir la sortie de manière structurée.

0
Florian