web-dev-qa-db-fra.com

Comment obtenir la sortie de la console en C++ avec un programme Windows?

Si j’ai un programme Windows C++ natif (c’est-à-dire que le point d’entrée est WinMain), comment puis-je afficher le résultat des fonctions de la console comme std :: cout?

27
Obediah Stane

Extraire Ajout d’E/S de console à une application d’interface graphique Win32 . Cela peut vous aider à faire ce que vous voulez. 

Si vous n'avez pas ou ne pouvez pas modifier le code, essayez les suggestions trouvées ici pour rediriger la sortie de la console vers un fichier.


Edit: bit de nécromancie de thread ici. J'ai d'abord répondu à cela il y a 9 ans, au tout début de la SO, avant l'entrée en vigueur de la (bonne) politique de réponses non-link-only. Je republierai le code de l'article original dans l'espoir d'expier mes péchés passés.

guicon.cpp - Une fonction de redirection de console

#include <windows.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>
#include <fstream>
#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif
// maximum mumber of lines the output console should have
static const Word MAX_CONSOLE_LINES = 500;
#ifdef _DEBUG
void RedirectIOToConsole()
{
    int hConHandle;
    long lStdHandle;
    CONSOLE_SCREEN_BUFFER_INFO coninfo;
    FILE *fp;

    // allocate a console for this app
    AllocConsole();

    // set the screen buffer to be big enough to let us scroll text
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
    coninfo.dwSize.Y = MAX_CONSOLE_LINES;
    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);

    // redirect unbuffered STDOUT to the console
    lStdHandle = (long)GetStdHandle(STD_OUTPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );
    *stdout = *fp;
    setvbuf( stdout, NULL, _IONBF, 0 );

    // redirect unbuffered STDIN to the console
    lStdHandle = (long)GetStdHandle(STD_INPUT_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "r" );
    *stdin = *fp;
    setvbuf( stdin, NULL, _IONBF, 0 );

    // redirect unbuffered STDERR to the console
    lStdHandle = (long)GetStdHandle(STD_ERROR_HANDLE);
    hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
    fp = _fdopen( hConHandle, "w" );
    *stderr = *fp;
    setvbuf( stderr, NULL, _IONBF, 0 );

    // make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
    // point to console as well
    ios::sync_with_stdio();
}

#endif
//End of File

guicon.h - Interface pour la fonction de redirection de console

#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG

void RedirectIOToConsole();

#endif
#endif

// End of File

test.cpp - Démonstration de la redirection de console

#include <windows.h>
#include <iostream>
#include <fstream>
#include <conio.h>
#include <stdio.h>
#ifndef _USE_OLD_OSTREAMS
using namespace std;
#endif
#include "guicon.h"


#include <crtdbg.h>

int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    #ifdef _DEBUG
    RedirectIOToConsole();
    #endif
    int iVar;

    // test stdio
    fprintf(stdout, "Test output to stdout\n");
    fprintf(stderr, "Test output to stderr\n");
    fprintf(stdout, "Enter an integer to test stdin: ");
    scanf("%d", &iVar);
    printf("You entered %d\n", iVar);

    //test iostreams
    cout << "Test output to cout" << endl;
    cerr << "Test output to cerr" << endl;
    clog << "Test output to clog" << endl;
    cout << "Enter an integer to test cin: ";
    cin >> iVar;
    cout << "You entered " << iVar << endl;
    #ifndef _USE_OLD_IOSTREAMS

    // test wide iostreams
    wcout << L"Test output to wcout" << endl;
    wcerr << L"Test output to wcerr" << endl;
    wclog << L"Test output to wclog" << endl;
    wcout << L"Enter an integer to test wcin: ";
    wcin >> iVar;
    wcout << L"You entered " << iVar << endl;
    #endif

    // test CrtDbg output
    _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
    _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR);
    _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
    _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR);
    _RPT0(_CRT_WARN, "This is testing _CRT_WARN output\n");
    _RPT0(_CRT_ERROR, "This is testing _CRT_ERROR output\n");
    _ASSERT( 0 && "testing _ASSERT" );
    _ASSERTE( 0 && "testing _ASSERTE" );
    Sleep(2000);
    return 0;
}

//End of File
22
luke

Vous pouvez également rouvrir les flux cout et cerr pour les exporter dans un fichier. Ce qui suit devrait fonctionner pour cela:

#include <iostream>
#include <fstream>

int main ()
{
    std::ofstream file;
    file.open ("cout.txt");
    std::streambuf* sbuf = std::cout.rdbuf();
    std::cout.rdbuf(file.rdbuf());
    //cout is now pointing to a file
    return 0;
}
9
workmad3

Utiliser une combinaison de la réponse de luke et la réponse de Roger ici a fonctionné pour moi dans mon projet d'application Windows Desktop.

void RedirectIOToConsole() {

    //Create a console for this application
    AllocConsole();

    // Get STDOUT handle
    HANDLE ConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    int SystemOutput = _open_osfhandle(intptr_t(ConsoleOutput), _O_TEXT);
    FILE *COutputHandle = _fdopen(SystemOutput, "w");

    // Get STDERR handle
    HANDLE ConsoleError = GetStdHandle(STD_ERROR_HANDLE);
    int SystemError = _open_osfhandle(intptr_t(ConsoleError), _O_TEXT);
    FILE *CErrorHandle = _fdopen(SystemError, "w");

    // Get STDIN handle
    HANDLE ConsoleInput = GetStdHandle(STD_INPUT_HANDLE);
    int SystemInput = _open_osfhandle(intptr_t(ConsoleInput), _O_TEXT);
    FILE *CInputHandle = _fdopen(SystemInput, "r");

    //make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog point to console as well
    ios::sync_with_stdio(true);

    // Redirect the CRT standard input, output, and error handles to the console
    freopen_s(&CInputHandle, "CONIN$", "r", stdin);
    freopen_s(&COutputHandle, "CONOUT$", "w", stdout);
    freopen_s(&CErrorHandle, "CONOUT$", "w", stderr);

    //Clear the error state for each of the C++ standard stream objects. We need to do this, as
    //attempts to access the standard streams before they refer to a valid target will cause the
    //iostream objects to enter an error state. In versions of Visual Studio after 2005, this seems
    //to always occur during startup regardless of whether anything has been read from or written to
    //the console or not.
    std::wcout.clear();
    std::cout.clear();
    std::wcerr.clear();
    std::cerr.clear();
    std::wcin.clear();
    std::cin.clear();

}
4
Sev

créer un canal, exécutez la console du programme CreateProcess () et lisez-la avec ReadFile () ou écrivez-la dans la console WriteFile () 

    HANDLE hRead ; // ConsoleStdInput
    HANDLE hWrite; // ConsoleStdOutput and ConsoleStdError

    STARTUPINFO           stiConsole;
    SECURITY_ATTRIBUTES   segConsole;
    PROCESS_INFORMATION   priConsole;

    segConsole.nLength = sizeof(segConsole);
    segConsole.lpSecurityDescriptor = NULL;
    segConsole.bInheritHandle = TRUE;

if(CreatePipe(&hRead,&hWrite,&segConsole,0) )
{

    FillMemory(&stiConsole,sizeof(stiConsole),0);
    stiConsole.cb = sizeof(stiConsole);
GetStartupInfo(&stiConsole);
stiConsole.hStdOutput = hWrite;
stiConsole.hStdError  = hWrite;
stiConsole.dwFlags    = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
stiConsole.wShowWindow = SW_HIDE; // execute hide 

    if(CreateProcess(NULL, "c:\\teste.exe",NULL,NULL,TRUE,NULL,
      NULL,NULL,&stiConsole,&priConsole) == TRUE)
    {
        //readfile and/or writefile
}    

3
denis

Si vous envoyez la sortie de votre programme dans un fichier ou un canal, par exemple,.

myprogram.exe > file.txt
myprogram.exe | anotherprogram.exe

ou vous appelez votre programme à partir d'un autre programme et capturez sa sortie via un canal, vous n'avez pas besoin de changer quoi que ce soit. Cela fonctionnera simplement, même si le point d’entrée est WinMain.

Toutefois, si vous exécutez votre programme dans une console ou dans Visual Studio, la sortie n'apparaîtra pas dans la console ni dans la fenêtre de sortie de Visual Studio. Si vous voulez voir la sortie "en direct", essayez l'une des autres réponses.

En gros, cela signifie que la sortie standard fonctionne comme avec les applications console, mais elle n’est pas connectée à une console dans laquelle vous exécutez votre application, et il ne semble pas y avoir de moyen facile de le faire (toutes les autres solutions présentées ici se connectent. la sortie dans une nouvelle fenêtre de la console qui apparaîtra lorsque vous exécuterez votre application, même à partir d’une autre console).

3
Florian Winter

Ne me citez pas là-dessus, mais l'API Win32 console pourrait être ce que vous cherchez. Cependant, si vous ne faites que cela à des fins de débogage, vous voudrez peut-être mieux exécuter DebugView et appeler la fonction DbgPrint .

Bien entendu, cela suppose que votre application souhaite envoyer la sortie de la console et non la lire à partir d'une autre application. Dans ce cas, les pipes pourraient être votre ami.

2
Chris Charabaruk

Sélectionnez Projet> Propriétés du projet> Éditeur de liens> Système et dans le volet de droite, définissez Sous-systèmes option sur Console (/ SUBSYSTEM: CONSOLE)

Ensuite, compilez votre programme et exécutez-le à partir de la console pour voir si la commande Invite affiche vos sorties ou non.

1
Kamran Bigdely

En réalité, il existe une solution beaucoup plus simple que celle proposée jusqu'à présent. Votre programme Windows aura une fonction WinMain alors ajoutez simplement cette fonction principale "factice"

int main()
{
   return WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(), SW_SHOWNORMAL);
}

Vous pouvez maintenant compiler en utilisant MSVC comme ceci

cl /nologo /c /EHsc myprog.c
link /nologo /out:myprog.exe /subsystem:console myprog.obj user32.lib gdi32.lib

(vous devrez peut-être ajouter plus de liens de bibliothèque)

Lorsque vous exécutez le programme, toute variable printf sera écrite dans la commande Invite.

Si vous utilisez gcc (mingw) pour compiler pour Windows, vous n’avez pas besoin d’une fonction principale factice,

gcc -o myprog.exe myprog.c -luser32 -lgdi32

(c.-à-d. évitez d'utiliser l'indicateur -mwindows qui empêchera l'écriture sur une console. Cet indicateur sera utile lors de la création de la version finale de l'interface graphique) De nouveau, vous devrez peut-être spécifier davantage de bibliothèques si vous utilisez davantage de fonctionnalités de Windows.

0
John Blackburn

Puisqu'il n'y a pas de fenêtre de console, c'est impossible difficile. (Apprenez quelque chose de nouveau chaque jour - je ne connaissais jamais les fonctions de la console!)

Est-il possible pour vous de remplacer vos appels de sortie? J'utiliserai souvent TRACE ou OutputDebugString pour envoyer des informations à la fenêtre de sortie de Visual Studio.

0
Mark Ransom