39

「良いこと」を行うサードパーティのライブラリにアクセスできます。stdoutにステータスメッセージと進行状況メッセージを発行します。コンソールアプリケーションでは、これらのメッセージを問題なく表示できます。Windowsアプリケーションでは、ビットバケットに移動するだけです。

stdoutとstderrをテキストコントロールまたは他の表示可能な場所にリダイレクトする非常に簡単な方法はありますか?理想的には、これはサードパーティのコードの再コンパイルを必要としません。それは低レベルで蒸気を遮断するだけです。ヘッダーを#includeし、初期化関数を呼び出して、ライブラリを次のようにリンクするソリューションが必要です...

#include "redirectStdFiles.h"

void function(args...)
{
  TextControl* text = new TextControl(args...);
  initializeRedirectLibrary(text, ...);

  printf("Message that will show up in the TextControl\n");
  std::cout << "Another message that also shows up in TextControl\n";
}

特定のGUIライブラリに関連付けられないように、オーバーライドできるインターフェイスを使用した方がよいでしょう。

class StdFilesRedirector
{
  public:
    writeStdout(std::string const& message) = 0;
    writeStderr(std::string const& errorMessage) = 0;
    readStdin(std::string &putReadStringHere) = 0;
};

私はただ夢を見ていますか?または、誰かがこのようなことをすることができる何かを知っていますか?

2つの答えの後で編集する:ファイルをリダイレクトするためにfreopenを使用することは良い最初のステップだと思います。完全なソリューションを得るには、ファイルを読み取って出力を表示するために新しいスレッドを作成する必要があります。デバッグの場合、cygwinシェルウィンドウで「tail-f」を実行するだけで十分です。より洗練されたアプリケーションの場合...これを書きたいのですが...スレッドを作成するための追加の作業などがあります。

4

8 に答える 8

19

( CreatePipe()を使用して)パイプを作成し、 SetStdHandle()を使用して stdout をその書き込み側にアタッチする必要があります。次に、 ReadFile()を使用してパイプの読み取り側から読み取り、そこから取得したテキストを好きな場所に配置できます。

于 2009-02-21T21:16:19.903 に答える
18

freopenを使用して、stdout、stderr、およびstdinをリダイレクトできます。

上記のリンクから:

/* freopen example: redirecting stdout */
#include <stdio.h>

int main ()
{
  freopen ("myfile.txt","w",stdout);
  printf ("This sentence is redirected to a file.");
  fclose (stdout);
  return 0;
}

次のように、コマンドプロンプトからプログラムを実行することもできます。

a.exe > stdout.txt 2> stderr.txt
于 2009-02-21T20:54:40.187 に答える
15

あなたはおそらくそれらの線に沿って何かを探しています:

    #define OUT_BUFF_SIZE 512

    int main(int argc, char* argv[])
    {
        printf("1: stdout\n");

        StdOutRedirect stdoutRedirect(512);
        stdoutRedirect.Start();
        printf("2: redirected stdout\n");
        stdoutRedirect.Stop();

        printf("3: stdout\n");

        stdoutRedirect.Start();
        printf("4: redirected stdout\n");
        stdoutRedirect.Stop();

        printf("5: stdout\n");

        char szBuffer[OUT_BUFF_SIZE];
        int nOutRead = stdoutRedirect.GetBuffer(szBuffer,OUT_BUFF_SIZE);
        if(nOutRead)
            printf("Redirected outputs: \n%s\n",szBuffer);

        return 0;
    }

このクラスはそれを行います:

#include <windows.h>

#include <stdio.h>
#include <fcntl.h>
#include <io.h>
#include <iostream>

#ifndef _USE_OLD_IOSTREAMS
using namespace std;
#endif

#define READ_FD 0
#define WRITE_FD 1

#define CHECK(a) if ((a)!= 0) return -1;

class StdOutRedirect
{
    public:
        StdOutRedirect(int bufferSize);
        ~StdOutRedirect();

        int Start();
        int Stop();
        int GetBuffer(char *buffer, int size);

    private:
        int fdStdOutPipe[2];
        int fdStdOut;
};

StdOutRedirect::~StdOutRedirect()
{
    _close(fdStdOut);
    _close(fdStdOutPipe[WRITE_FD]);
    _close(fdStdOutPipe[READ_FD]);
}
StdOutRedirect::StdOutRedirect(int bufferSize)
{
    if (_pipe(fdStdOutPipe, bufferSize, O_TEXT)!=0)
    {
        //treat error eventually
    }
    fdStdOut = _dup(_fileno(stdout));
}

int StdOutRedirect::Start()
{
    fflush( stdout );
    CHECK(_dup2(fdStdOutPipe[WRITE_FD], _fileno(stdout)));
    ios::sync_with_stdio();
    setvbuf( stdout, NULL, _IONBF, 0 ); // absolutely needed
    return 0;
}

int StdOutRedirect::Stop()
{
    CHECK(_dup2(fdStdOut, _fileno(stdout)));
    ios::sync_with_stdio();
    return 0;
}

int StdOutRedirect::GetBuffer(char *buffer, int size)
{
    int nOutRead = _read(fdStdOutPipe[READ_FD], buffer, size);
    buffer[nOutRead] = '\0';
    return nOutRead;
}

結果は次のとおりです。

1: stdout
3: stdout
5: stdout
Redirected outputs:
2: redirected stdout
4: redirected stdout
于 2009-03-05T23:26:54.310 に答える
7

CreateProcess()を使用してプロセスを作成する場合、HANDLEstdoutとstderrが書き込まれる先を選択できます。これHANDLEは、出力を送信するファイルにすることができます。

これにより、コードを再コンパイルせずに使用できるようになります。system()実行するだけで、使用するかどうかの代わりに、を使用しますCreateProcess()

与えるハンドルはCreateProcess()、作成したパイプのハンドルにすることもできます。その後、パイプから読み取り、データを使用して別のことを行うことができます。

于 2009-02-21T21:09:57.047 に答える
4

あなたはcoutまたはcerrでこのようなことをすることができます:

// open a file stream
ofstream out("filename");
// save cout's stream buffer
streambuf *sb = cout.rdbuf();
// point cout's stream buffer to that of the open file
cout.rdbuf(out.rdbuf());
// now you can print to file by writing to cout
cout << "Hello, world!";
// restore cout's buffer back
cout.rdbuf(sb);

std::stringstreamまたは、から派生したまたは他のクラスを使用してこれを行うことができますstd::ostream

stdoutをリダイレクトするには、ファイルハンドルを再度開く必要があります。このスレッドには、この性質に関するいくつかのアイデアがあります。

于 2009-02-21T21:14:10.063 に答える
2

これは私がすることです:

  1. CreatePipe()。
  2. 新しいプロセスの stdout として使用される CreatePipe() からのハンドルを持つ CreateProcess()。
  3. そのハンドルで ReadFile() を時々呼び出すタイマーまたはスレッドを作成し、読み取ったデータをテキストボックスなどに入れます。
于 2009-02-21T23:08:39.540 に答える
2

ここではconsoleMain、独自のエントリ ポイントをオーバーライドする新しいエントリ ポイントを設定します。

  1. アプリケーションのエントリ ポイントを決定します。VisualStudio で、Project Properties/Linker/Advanced/Entry Pointを選択します。と呼びましょうdefaultMain
  2. ソース コードのどこかで、元のエントリ ポイント (チェーンできるようにするため) と新しいエントリ ポイントを宣言します。extern "C"名前マングリングを防ぐために、両方を宣言する必要があります。

    extern "C"
    {
      int defaultMain (void);
      int consoleMain (void);
    }
    
  3. エントリーポイント機能を実装。

    __declspec(noinline) int consoleMain (void)
    {
      // __debugbreak(); // Break into the program right at the entry point!
      AllocConsole();    // Create a new console
      freopen("CON", "w", stdout);
      freopen("CON", "w", stderr);
      freopen("CON", "r", stdin); // Note: "r", not "w".
      return defaultMain();
    }
    
  4. テスト コードをどこかに追加します (ボタン クリック アクションなど)

    fwprintf(stdout, L"This is a test to stdout\n");
    fwprintf(stderr, L"This is a test to stderr\n");
    cout<<"Enter an Integer Number Followed by ENTER to Continue" << endl;
    _flushall();
    int i = 0;
    int Result = wscanf( L"%d", &i);
    printf ("Read %d from console. Result = %d\n", i, Result);
    
  5. consoleMain新しいエントリ ポイントとして設定します ( Project Properties/Linker/Advanced/Entry Point )。
于 2015-11-26T16:02:42.217 に答える
1

grayfade による回答のgamedevリンクのおかげで、この単純なコードを記述してテストすることができました

AllocConsole();

*stdout = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_OUTPUT_HANDLE), _O_WRONLY), _T("a"));
*stderr = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_ERROR_HANDLE), _O_WRONLY), _T("a"));
*stdin = *_tfdopen(_open_osfhandle((intptr_t) GetStdHandle(STD_INPUT_HANDLE), _O_WRONLY), _T("r"));


printf("A printf to stdout\n");
std::cout << "A << to std::cout\n";
std::cerr << "A << to std::cerr\n";
std::string input;
std::cin >> input;

std::cout << "value read from std::cin is " << input << std::endl;

動作し、デバッグには十分です。テキストをより魅力的な GUI 要素にするには、もう少し手間がかかります。

于 2009-02-23T01:09:13.577 に答える