0

stderr子プロセスから読み込もうとしています。データは、 で作成されたテキスト行ですsprintf(stderr, "some debug info\n")ReadFileE完了ルーチンで x を使用しています。テキストの行数や各行の長さはわかりません。nNumberOfBytesToReadでは、パラメータとして何を入力すればよいでしょうか。

私の推測では、バッファの最大サイズを入れて、4k にします。それが最適なサイズかどうかはわかりませんが。書き込まれた行stderrが 4k より短い場合、完了ルーチンは起動しないと思います。4k に到達してもまだデータが残っている場合はReadFileEx、完了ルーチン内で別のデータを起動する必要があると思います。GetLastErrorが返されるため、これが事実であることがわかりますERROR_MORE_DATA。バッファがいっぱいではなく、子プロセスが終了したときに呼び出しを受けることを望んでいます。stderr子プロセスを作成したときに子プロセスに書き込みハンドルを渡したので、子プロセスが終了したときに完了コールバックを受け取るかどうかはわかりません。そのハンドルを閉じたときにコールバックを受け取るかもしれません。wrtstderr?

プロセスとハンドルの作成方法の疑似コードを次に示します。

Attr.bInheritHandle = true
CreatePipe(&hr, &hw, &Attr, 0) and SetHandleInformation(hX, HANDLE_FLAG_INHERIT) on hX the child uses.
Si.hStdXXX = handles from CreatePipe that child uses
CreateProcess(inherit=true, &Si)

詳細 (Tx 拡張機能は、エラーをスローするラッパーです):

HANDLE Create() {
    STARTUPINFO SI, *pSI = NULL;
    bool fInherit = m_fInherit;
    if (m_fStdOut || m_fStdIn || m_fStdErr) {
        fInherit = true;
        SECURITY_ATTRIBUTES Attr;
        Attr.nLength = sizeof(SECURITY_ATTRIBUTES); 
        Attr.bInheritHandle = TRUE; 
        Attr.lpSecurityDescriptor = NULL;
        if (m_fStdOut) // Create a pipe for the child process's STDOUT. The child will use the write.
            CHandle::CreatePipe(m_hStdOutR, m_hStdOutW, &Attr, CP_INHERIT_WRITE);
        if (m_fStdErr) // Create a pipe for the child process's STDERR. The child will use the write.
            CHandle::CreatePipe(m_hStdErrR, m_hStdErrW, &Attr, CP_INHERIT_WRITE);
        if (m_fStdIn) // Create a pipe for the child process's STDIN. The child will use the read.
            CHandle::CreatePipe(m_hStdInR, m_hStdInW, &Attr, CP_INHERIT_READ);
        // Set up members of the STARTUPINFO structure. 
        // This structure specifies the STDIN and STDOUT handles for redirection.
        ZeroStruct(SI);
        SI.cb = sizeof(STARTUPINFO); 
        SI.hStdError = m_hStdErrW, SI.hStdOutput = m_hStdOutW, SI.hStdInput = m_hStdInR;
        SI.dwFlags |= STARTF_USESTDHANDLES;
        pSI = &SI;
    }
    //  m_fCpu, m_fNuma are masks to set affinity to cpus or numas
    CreateProcessTx(NULL, m_szCmdLine, fInherit, m_fFlags, pSI, &m_pi, m_fCpu, m_fNuma, 5);
    m_hProc = m_pi.hProcess;
    m_hThread = m_pi.hThread;
    if (!m_fThread)
        m_hThread.Close();
    return m_hProc;
}

static void CreatePipe(CHandle &hRead, CHandle &hWrite, SECURITY_ATTRIBUTES* pAttr, BYTE fInheritMask) {
    HANDLE hReadTmp = NULL, hWriteTmp = NULL;
    CreatePipeTx(hReadTmp, hWriteTmp, pAttr);
    SetHandleInformation(hReadTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_READ) ? HANDLE_FLAG_INHERIT : 0); 
    SetHandleInformation(hWriteTmp, HANDLE_FLAG_INHERIT, (fInheritMask&CP_INHERIT_WRITE) ? HANDLE_FLAG_INHERIT : 0);
    hRead = hReadTmp;
    hWrite = hWriteTmp;
}
4

1 に答える 1

2

で作成された匿名パイプは、CreatePipe非同期には使用できません。Windows SDK ドキュメントから:

非同期 (オーバーラップ) 読み取りおよび書き込み操作は、匿名パイプではサポートされていません。つまり、無名パイプで ReadFileEx および WriteFileEx 関数を使用することはできません。>さらに、ReadFile および WriteFile の lpOverlapped パラメータは、これらの関数が無名パイプで使用される場合には無視されます。

基本的CreatePipeにフラグを受け入れませんFILE_FLAG_OVERLAPPED。非同期 I/O では、ファイル ハンドルを作成するときにフラグを使用する必要があります。

CreateNamedPipe名前付きパイプを作成するには、 を使用する必要があります。匿名パイプでの I/O のオーバーラップに関する質問には、MyCreatePipeEx使用できる代替関数へのリンクが含まれています。

もう一方の端で閉じられたパイプから読み取りを試行した後、完了ポートは長さゼロの読み取りイベントを受け取る必要があります。

クライアント プロセスから可変量のデータを読み取るには、必要なサイズの読み取り要求を発行し、要求したよりも短い読み取りイベントを処理できるように準備します。短いがゼロでない長さを EOF と解釈しないでください。長さゼロの読み取りまたはエラーが発生するまで、読み取り要求を発行し続けます。

また、スレッドが変更可能な状態WaitForMultipleObjectsにあるときにのみ呼び出されるため、完了ルーチンでは機能しません。引数を true に設定して使用します。この関数は、1 つ以上の完了ルーチンを実行した後に戻ります。その場合、おそらくすぐにもう一度電話したいと思うでしょう。WaitForMultipleObjectExbAlertableWAIT_IO_COMPLETIONWaitForMultipleObjectEx

于 2014-07-23T19:01:05.907 に答える