web-dev-qa-db-ja.com

Windowsプログラムを使用してC ++でコンソール出力を取得するにはどうすればよいですか?

ネイティブC++ Windowsプログラム(つまり、エントリポイントがWinMain)がある場合、std :: coutなどのコンソール関数からの出力を表示するにはどうすればよいですか?

30
Obediah Stane

Win32 GUIアプリへのコンソールI/Oの追加 を確認してください。これは、あなたが望むことをするのに役立つかもしれません。

コードがない場合、またはコードを変更できない場合は、見つかった提案を試してください here コンソール出力をファイルにリダイレクトします。


編集:ここでスレッドのネクロマンシーのビット。私はこの9年前、SOの初期に、非リンクのみの回答の(良い)ポリシーが発効する前に最初に回答しました。過去の罪をaうために、元の記事のコードを再投稿します。

guicon.cpp-コンソールリダイレクト機能

#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-コンソールリダイレクト機能へのインターフェース

#ifndef __GUICON_H__
#define __GUICON_H__
#ifdef _DEBUG

void RedirectIOToConsole();

#endif
#endif

// End of File

test.cpp-コンソールリダイレクトのデモ

#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
21
luke

Coutおよびcerrストリームを再度開いて、ファイルに出力することもできます。これには以下が有効です。

#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;
}
10
workmad3

luke's answerRoger's answer here の組み合わせを使用すると、Windowsデスクトップアプリケーションプロジェクトでうまくいきました。

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

}
5
Sev

パイプの作成、プログラムコンソールCreateProcess()の実行、ReadFile()による読み取り、またはコンソール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

プログラムの出力をファイルまたはパイプに送信する場合、たとえば.

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

または、別のプログラムからプログラムを呼び出し、パイプを介してその出力をキャプチャしている場合は、何も変更する必要はありません。エントリポイントがWinMainであっても機能します。

ただし、コンソールまたはVisual Studioでプログラムを実行している場合、出力はコンソールまたはVisual Studioの[出力]ウィンドウに表示されません。出力を「ライブ」で表示する場合は、他の回答のいずれかを試してください。

基本的に、これは標準出力がコンソールアプリケーションと同じように機能することを意味しますが、アプリケーションを実行しているコンソールに接続されておらず、それを行う簡単な方法はないようです(ここで紹介する他のすべてのソリューションは接続します別のコンソールからであっても、アプリケーションの実行時にポップアップする新しいコンソールウィンドウへの出力)。

3
Florian Winter

実際、これまでに提案されたものよりもはるかに簡単な解決策があります。 WindowsプログラムにはWinMain関数があるため、この「ダミー」メイン関数も追加してください。

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

このようにMSVCを使用してコンパイルできるようになりました

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

(ライブラリリンクをさらに追加する必要がある場合があります)

プログラムを実行すると、printfがコマンドプロンプトに書き込まれます。

Gcc(mingw)を使用してWindows用にコンパイルする場合、ダミーのメイン関数は必要ありません。

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

(つまり、-mwindowsフラグは、コンソールへの書き込みを防ぎます。このフラグは、最終的なGUIリリースを作成するときに役立ちます)繰り返しますが、より多くのWindows機能を使用する場合は、より多くのライブラリを指定する必要があります)

2
John Blackburn

私にこれを引用しないでください、しかし、Win32 コンソールAPI はあなたが探しているものかもしれません。ただし、デバッグのためだけにこれを行う場合は、 DebugView を実行して DbgPrint 関数を呼び出すことに興味があるかもしれません。

もちろん、これは、アプリケーションが別のアプリケーションからそれを読み取らずに、コンソール出力を送信することを前提としています。その場合、パイプがあなたの友達かもしれません。

2

[プロジェクト]> [プロジェクトのプロパティ]> [リンカー]> [システム]に移動し、右ペインでSubSystemsオプションをConsole(/ SUBSYSTEM:CONSOLE)に設定します

次に、プログラムをコンパイルしてコンソールから実行し、コマンドプロンプトが出力を表示するかどうかを確認します。

2
Kamran Bigdely

これを正しく機能させるために、今日一日中過ごしました。 luke's および Sev's のようなWeb上の回答が見つかりました.

メソッドは機能しますが、FreeConsoleを呼び出すか、アプリケーションを正常に終了するだけでコンソールを終了すると問題が発生します。デバッグモードでは、CRTクリーンアップコードに無効なファイルハンドルに関するデバッグアサーションが表示されます。

この問題の原因の一部は、誰もが使用している過度に複雑なリダイレクトプロセスであり、一部は終了する前に標準のIOストリームがリダイレクトされないためです。

このプロセスで_open_osfhandle_fdopenを使用する必要性がまったくわかりません。

これは私のために働いている完全なソリューションです:

コンソール標準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;
}

コンソールのリリース:

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

コンソールバッファーのサイズ変更:

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

新しいコンソールの割り当て:

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

親のコンソールへの接続:

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

WinMainからの呼び出し:

/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

コンソールウィンドウがないため、これは 不可能な 難しい。 (毎日新しいことを学んでください-コンソールの機能については知りませんでした!)

出力呼び出しを置き換えることは可能ですか?多くの場合、TRACEまたはOutputDebugStringを使用して、情報をVisual Studio出力ウィンドウに送信します。

0
Mark Ransom

前述のように、 there および there 最も簡単な解決策は、プロジェクトプロパティページを使用してCONSOLEWINDOWS SubSytemsを切り替えることです。コンソール出力を自由に有効または無効にします。

Project Properties

あなたのプログラムは、両方の設定がコンパイルされていることを確認するために、mainWinMainエントリポイントが必要です。 main関数は、たとえば以下に示すように、単にWinMainを呼び出します。

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

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