webentwicklung-frage-antwort-db.com.de

Wie erhalte ich mit einem Windows-Programm eine Konsolenausgabe in C++?

Wenn ich ein natives C++ - Windows-Programm habe (d. H. Der Einstiegspunkt ist WinMain), wie kann ich die Ausgabe von Konsolenfunktionen wie std :: cout anzeigen?

27
Obediah Stane

Check out Hinzufügen von Konsolen-E/A zu einer Win32-GUI-App . Dies kann Ihnen helfen, das zu tun, was Sie möchten. 

Wenn Sie den Code nicht haben oder nicht ändern können, versuchen Sie es mit den Vorschlägen in here , um die Konsolenausgabe in eine Datei umzuleiten.


Edit: etwas Thread-Nekromanz hier. Ich habe diese Frage vor 9 Jahren, in den frühen Tagen der SO, beantwortet, bevor die (gute) Politik der Nicht-Link-Antworten in Kraft trat. Ich werde den Code aus dem ursprünglichen Artikel in der Hoffnung veröffentlichen, meine früheren Sünden zu büßen.

guicon.cpp - Eine Konsolenumleitungsfunktion

#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 - Schnittstelle zur Konsolenumleitungsfunktion

#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG

void RedirectIOToConsole();

#endif
#endif

// End of File

test.cpp - Demonstration der Konsolenumleitung

#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

Sie können auch die Cout- und Cerr-Streams erneut öffnen, um sie in eine Datei auszugeben. Folgendes sollte dafür funktionieren:

#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

Mit einer Kombination aus Lukes Antwort und Rogers Antwort hier arbeitete ich für mein Windows Desktop Application-Projekt.

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

erstellen Sie eine Pipe, führen Sie die Programmkonsole CreateProcess () aus und lesen Sie sie mit ReadFile () oder schreibt in die Konsole 

    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

Wenn Sie die Ausgabe Ihres Programms in eine Datei oder Pipe senden, z.

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

oder Sie rufen Ihr Programm von einem anderen Programm auf und erfassen dessen Ausgabe über eine Pipe. Dann brauchen Sie nichts zu ändern. Es funktioniert auch, wenn der Einstiegspunkt WinMain ist.

Wenn Sie Ihr Programm jedoch in einer Konsole oder in Visual Studio ausführen, wird die Ausgabe nicht in der Konsole oder im Ausgabefenster von Visual Studio angezeigt. Wenn Sie die Ausgabe "live" sehen möchten, versuchen Sie eine der anderen Antworten.

Im Grunde bedeutet dies, dass die Standardausgabe genau wie bei Konsolenanwendungen funktioniert, sie ist jedoch nicht mit einer Konsole verbunden, in der Sie Ihre Anwendung ausführen. Dies scheint nicht einfach zu sein (alle anderen hier vorgestellten Lösungen verbinden sich) die Ausgabe in ein neues Konsolenfenster, das beim Ausführen der Anwendung (auch von einer anderen Konsole aus) erscheint.

3
Florian Winter

Zitieren Sie mich nicht dazu, aber die Win32 console API ist vielleicht das, wonach Sie suchen. Wenn Sie dies nur zu Debugging-Zwecken tun, sind Sie möglicherweise mehr daran interessiert, DebugView auszuführen und die Funktion DbgPrint aufzurufen.

Dies setzt natürlich voraus, dass Ihre Anwendung die Konsolenausgabe sendet und nicht aus einer anderen Anwendung liest. In diesem Fall könnten Pfeifen Ihr Freund sein.

2

Verbrachte heute den ganzen Tag damit, dies richtig zum Laufen zu bringen. Gefundene Antworten im ganzen Web, die aussehen wie luke's und Sev's .

Die Methode funktioniert, aber das Problem tritt auf, wenn ich die Konsole beende, indem ich FreeConsole aufrufe oder die Anwendung einfach normal beende. Im Debug-Modus werden Debug-Aussagen zu ungültigen Datei-Handles im CRT-Bereinigungscode angezeigt.

Ich denke, das Problem wird teilweise durch den übermäßig komplizierten Umleitungsprozess verursacht, den alle verwenden, und teilweise, weil die Standard-IO -Streams vor dem Beenden nicht umgeleitet werden.

Ich verstehe überhaupt nicht die Notwendigkeit, _open_osfhandle Und _fdopen In diesem Prozess zu verwenden.

Dies ist die Komplettlösung, die für mich funktioniert:

Umleiten von Console Standard IO:

bool RedirectConsoleIO()
{
    bool result = true;
    FILE* fp;

    // Redirect STDIN if the console has an input handle
    if (GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)
        if (freopen_s(&fp, "CONIN$", "r", stdin) != 0)
            result = false;
        else
            setvbuf(stdin, NULL, _IONBF, 0);

    // Redirect STDOUT if the console has an output handle
    if (GetStdHandle(STD_OUTPUT_HANDLE) != INVALID_HANDLE_VALUE)
        if (freopen_s(&fp, "CONOUT$", "w", stdout) != 0)
            result = false;
        else
            setvbuf(stdout, NULL, _IONBF, 0);

    // Redirect STDERR if the console has an error handle
    if (GetStdHandle(STD_ERROR_HANDLE) != INVALID_HANDLE_VALUE)
        if (freopen_s(&fp, "CONOUT$", "w", stderr) != 0)
            result = false;
        else
            setvbuf(stderr, NULL, _IONBF, 0);

    // Make C++ standard streams point to console as well.
    ios::sync_with_stdio(true);

    // Clear the error state for each of the C++ standard streams.
    std::wcout.clear();
    std::cout.clear();
    std::wcerr.clear();
    std::cerr.clear();
    std::wcin.clear();
    std::cin.clear();

    return result;
}

Eine Konsole freigeben:

bool ReleaseConsole()
{
    bool result = true;
    FILE* fp;

    // Just to be safe, redirect standard IO to NUL before releasing.

    // Redirect STDIN to NUL
    if (freopen_s(&fp, "NUL:", "r", stdin) != 0)
        result = false;
    else
        setvbuf(stdin, NULL, _IONBF, 0);

    // Redirect STDOUT to NUL
    if (freopen_s(&fp, "NUL:", "w", stdout) != 0)
        result = false;
    else
        setvbuf(stdout, NULL, _IONBF, 0);

    // Redirect STDERR to NUL
    if (freopen_s(&fp, "NUL:", "w", stderr) != 0)
        result = false;
    else
        setvbuf(stderr, NULL, _IONBF, 0);

    // Detach from console
    if (!FreeConsole() || !result)
        return false;

    return true;
}

Größenänderung des Konsolenpuffers:

void AdjustConsoleBuffer(int16_t minLength)
{
    // Set the screen buffer to be big enough to scroll some text
    CONSOLE_SCREEN_BUFFER_INFO conInfo;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &conInfo);
    if (conInfo.dwSize.Y < minLength)
        conInfo.dwSize.Y = minLength;
    SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), conInfo.dwSize);
}

Zuweisen einer neuen Konsole:

bool CreateNewConsole(int16_t minLength)
{
    bool result = false;

    // Release any current console and redirect IO to NUL
    ReleaseConsole();

    // Attempt to create new console
    if (AllocConsole())
    {
        AdjustConsoleBuffer(minLength);
        result = RedirectConsoleIO();
    }

    return result;
}

Anfügen an die Elternkonsole:

bool AttachParentConsole(int16_t minLength)
{
    bool result = false;

    // Release any current console and redirect IO to NUL
    ReleaseConsole();

    // Attempt to attach to parent process's console
    if (AttachConsole(ATTACH_PARENT_PROCESS))
    {
        AdjustConsoleBuffer(minLength);
        result = RedirectConsoleIO();
    }

    return result;
}

Aufruf von WinMain:

Link mit /SUBSYSTEM:Windows

int APIENTRY WinMain(
    HINSTANCE /*hInstance*/,
    HINSTANCE /*hPrevInstance*/,
    LPTSTR    /*lpCmdLine*/,
    int       /*cmdShow*/)
{
    if (CreateNewConsole(1024))
    {
        int i;

        // 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", &i);
        printf("You entered %d\n", i);

        // 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 >> i;
        cout << "You entered " << i << endl;

        std::cout << endl << "Press any key to continue..." << endl;
        _getch();

        ReleaseConsole();
    }

    return 0;
};
1
Chris Olsen

Gehen Sie zu Projekt> Projekteigenschaften> Linker> System und setzen Sie im rechten Bereich SubSystems Option auf Console (/ SUBSYSTEM: CONSOLE)

Kompilieren Sie dann Ihr Programm und führen Sie es von der Konsole aus aus, um zu sehen, ob der Befehl Eingabeaufforderung Ihre Ausgaben anzeigt oder nicht.

1
Kamran Bigdely

Tatsächlich gibt es eine viel einfachere Lösung als bisher vorgeschlagen. Ihr Windows-Programm verfügt über eine WinMain-Funktion. Fügen Sie also einfach diese "Dummy" -Funktion hinzu

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

Sie können jetzt mit MSVC so kompilieren

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

(Sie müssen möglicherweise weitere Bibliothekslinks hinzufügen.)

Wenn Sie das Programm ausführen, wird eine beliebige printf in die Eingabeaufforderung geschrieben.

Wenn Sie gcc (mingw) zum Kompilieren für Windows verwenden, benötigen Sie keine Dummy-Hauptfunktion

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

(dh vermeiden Sie die Verwendung des Flags -mwindows, das das Schreiben auf einer Konsole verhindert. Dieses Flag wird beim Erstellen der endgültigen GUI-Version hilfreich sein.) Wenn Sie weitere Windows-Funktionen verwenden, müssen Sie möglicherweise mehr Bibliotheken angeben.

0
John Blackburn

Da es kein Konsolenfenster gibt, ist es das unmöglich schwer. (Lernen Sie jeden Tag etwas Neues - ich habe nie von den Konsolenfunktionen erfahren!)

Können Sie Ihre Ausgabeaufrufe ersetzen? Ich werde häufig TRACE oder OutputDebugString verwenden, um Informationen an das Visual Studio-Ausgabefenster zu senden.

0
Mark Ransom

Wie bereits erwähnt dort und dort besteht die einfachste Lösung darin, mithilfe Ihrer Projekteigenschaftenseiten zwischen den CONSOLE - und WINDOWS -Untersystemen zu wechseln Aktivieren oder Deaktivieren der Konsolenausgabe nach Belieben.

Project Properties

Ihr Programm benötigt nur die Einstiegspunkte main und WinMain, um sicherzustellen, dass beide Konfigurationen kompiliert werden. Die Funktion main ruft einfach WinMain auf, wie unten gezeigt:

int main()
{
cout << "Output standard\n";
cerr << "Output error\n";

return WinMain(GetModuleHandle(NULL), NULL, GetCommandLineA(), SW_SHOWNORMAL);
}
0
Slion