6

BSDプロジェクトの既存の C++ コードを独自のカスタム ラッパーでラップしており、できるだけ少ない変更でコードに統合したいと考えています。このコードはfprintf、エラーを記録/報告するためにstderrに出力するために使用します。

これを同じプロセス内の別の場所にリダイレクトしたい。Unix では、これを asocketpairと a で実行しましたthread。ソケットの一方の端は(への呼び出しを介して) stderrdup2を送信する場所であり、もう一方の端はスレッドで監視され、そこで出力を処理できます。

ただし、ソケットはファイル ハンドルと同じではないため、これはWindows では機能しません。

Web で見つけたすべてのドキュメントは、子プロセスからの出力をリダイレクトする方法を示していますが、これは私が望んでいるものではありません。出力が書き込まれるときに何らかのコールバックを取得する同じプロセス内でstderrをリダイレクトするにはどうすればよいですか? (そして、あなたがそう言う前に、私は試しましSetStdHandleたが、これを機能させる方法を見つけることができません)...

4

3 に答える 3

6

Windows でも同様の手法を使用できます。同じ概念に対して異なる単語を使用する必要があるだけです。:) この記事: http://msdn.microsoft.com/en-us/library/ms682499.aspxは win32 パイプを使用して別のプロセスからの I/O を処理します。同じプロセス内のスレッドで同じことを行うだけです。処理する。もちろん、あなたの場合、プロセスのどこからでも stderr へのすべての出力がコンシューマーにリダイレクトされます。

実際、必要なパズルのピースは_fdopen_open_osfhandleです。実際、私が何年も前にリリースしたいくつかのコードからの関連する例を次に示します。

DWORD CALLBACK DoDebugThread(void *)
{
    AllocConsole();
    SetConsoleTitle("Copilot Debugger");
    // The following is a really disgusting hack to make stdin and stdout attach
    // to the newly created console using the MSVC++ libraries. I hope other
    // operating systems don't need this kind of kludge.. :)
    stdout->_file = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), _O_TEXT);
    stdin->_file  = _open_osfhandle((long)GetStdHandle(STD_INPUT_HANDLE), _O_TEXT);
    debug();
    stdout->_file = -1;
    stdin->_file  = -1;
    FreeConsole();
    CPU_run();
    return 0;
}   

この場合、メイン プロセスは、stdio ハンドルでまったく開始されない GUI プロセスでした。コンソールを開き、適切なハンドルを stdout と stdin に押し込んで、debug() 関数 (stdio の対話型関数として設計されています) が新しく作成されたコンソールとやり取りできるようにします。いくつかのパイプを開いて、stderr をリダイレクトするために同じようなことを行うことができるはずです。

于 2008-08-11T11:05:37.820 に答える
3

MSVCRTが「OSハンドル」と呼ぶものはWin32ハンドルではなく、混乱させるために追加されたハンドルの別のレイヤーであることを覚えておく必要があります。MSVCRTは、stdin= 0、stdout= 1、stderr=2などのUnixハンドル番号をエミュレートしようとします。Win32ハンドルの番号は異なり、値は常に4の倍数になります。パイプを開いてすべてのハンドルを適切に構成するには、手を煩雑にする必要があります。MSVCRTソースコードとデバッガーを使用することはおそらく要件です。

于 2008-08-11T11:39:21.853 に答える
1

名前付きパイプを内部使用に使用したくないとのことです。CreatePipe()のドキュメントには、「匿名パイプは、一意の名前を持つ名前付きパイプを使用して実装されます。したがって、名前付きパイプへのハンドルを必要とする関数への名前付きパイプへのハンドルを渡すことができます。パイプ。" したがって、非同期読み取りの正しい設定で同様のパイプを作成する関数を作成することをお勧めします。私はGUIDを文字列(とを使用して生成)として使用して一意の名前を付け、重複するI / Oの正しい設定で名前付きパイプのサーバーとクライアントの端を作成する傾向がありますCoCreateGUID()StringFromIID()これとコードの詳細は、ここ: http://www.lenholgate.com/blog/2008/02/process-management-using-jobs-on-windows.html)。

オーバーラップしたI/OとI/O完了ポートを使用してファイルを読み取る必要があるコードを配線したら、データが到着すると非同期通知を受け取ります...しかし、私は十分にテストされたライブラリコードがかなりの量あり、すべてが実現します...

名前付きパイプを設定してから、OVERLAPPED構造内のイベントとオーバーラップした読み取りを実行し、イベントをチェックしてデータが利用可能かどうかを確認することはおそらく可能です...しかし、それを行うコードはありません。

于 2008-09-16T08:52:53.360 に答える