パイプ処理

以前javaエディタを作った時、コンパイル結果をパイプ経由で取得することにしました。
google先生で調べたら CreatePipe関数→ReadFile関数としなさい、とあったのでその通りにしました。


ところが実行中の標準出力も同じように取得してみたところ、その実行が終わるまでエディタが固まってしまいます。
というのも、ReadFile関数はブロック関数で、何か受信するまで処理を返さないからです。


ネットワーク関数でいうselectに相当するものはないかとMSDNを眺めていると、PeekNamedPipe関数というのがありました。
標準出力を覗き見る関数です。何かあれば(ReadFileするタイミング)教えてくれます。
NamedPipeなのに名前無しパイプも扱えます。(その変な名前のおかげで探すのに時間掛かりました^^;;)*1


while(1)
{
    // ウィンドウメッセージ処理
    ...

    // データがあるかどうか見る
    if (::PeekNamedPipe(hRead, NULL, 0, NULL, &dwRead, NULL)==0) {
        // 対象のプロセスが終了した
        break;
    }
    if (dwRead==0) {
        // データがない!
        ::Sleep(50);
        continue;
    }
    // 読み取る
    ::ReadFile(hRead, pBuffer.get(), nSize, &dwRead, NULL);
}


ということでした。

*1:Windows NT/2000:名前なしパイプは、一意の名前を持つ名前付きパイプとして実装されています。そのため、多くの場合、名前付きパイプのハンドルを必要とする関数に対して、名前なしパイプのハンドルを渡すことができます。」とあるのでXP以降は事情が変わる様子