8

子プロセスを作成し、その出力を読み取っています。子プロセスが出力()を作成するとき、私のコードは正常に機能しますが、プロセスが出力(cmd /c echo Hello World)を作成しない場合、ReadFileはハングしますcmd /c echo Hello World > output.txt。私はプロセスが終了した後にのみ読んでいます。

私はひどく間違ったことをしていますか?同期モードでこれを行う方法はありますか、それとも非同期モードを使用する必要がありますか?これはすべて別のスレッドで行われているため、これを機能させる唯一の方法でない限り、非同期モードが私にメリットをもたらすとは思いません。どうもありがとう!

saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
saAttr.bInheritHandle = TRUE; 
saAttr.lpSecurityDescriptor = NULL; 

CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0);
SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0);

memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
memset(&siStartInfo, 0, sizeof(STARTUPINFO));
siStartInfo.cb = sizeof(STARTUPINFO); 
siStartInfo.hStdError = g_hChildStd_OUT_Wr;
siStartInfo.hStdOutput = g_hChildStd_OUT_Wr;
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
CreateProcess(NULL, commandWideString, NULL, NULL, TRUE, 0, NULL, NULL, &siStartInfo, &piProcInfo);

while(1)
{
    GetExitCodeProcess(piProcInfo.hProcess, &processExitCode);
    if(processExitCode != STILL_ACTIVE)
        break;
    else
        Sleep(1);
}

*output = (char *)calloc(32, sizeof(char));
processOutputSize = 0;
while(1)
{
    bSuccess = ReadFile( g_hChildStd_OUT_Rd, processOutputTemp, 32, &dwRead, NULL);
    if(!bSuccess || !dwRead)
        break;
    memcpy(*output + processOutputSize, processOutputTemp, dwRead);
    processOutputSize += dwRead;
    if(dwRead == 32)
        *output = (char *)realloc(*output, processOutputSize + 32);
    else
    {
        memset(*output + processOutputSize, 0, 1);
        break;
    }
}
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
CloseHandle(g_hChildStd_OUT_Rd);
CloseHandle(g_hChildStd_OUT_Wr);
4

3 に答える 3

17

@Marcusがコメントで示唆しているように、出力パイプから読み取る前に、出力パイプの書き込み端を閉じる必要があります。

CloseHandle(g_hChildStd_OUT_Wr);

私にとって、これが本当の答えです。

于 2016-08-03T09:11:59.797 に答える
6

プロセスの出力をパイプにリダイレクトし、プロセスを開始し、終了するまで待ってから、出力を読み取ります。

問題は、Windowsが限られた量のデータのみをバッファリングすることです。したがって、プロセスの実行中にパイプを読み取る必要があります。そうしないと、パイプにこれ以上データを書き込めないため、プロセスがブロックされます。

于 2012-12-15T18:35:02.680 に答える
3

次のようなループでPeekNamedPipeを使用できます。

for (;;)
{
    DWORD bytesAvail = 0;
    if (!PeekNamedPipe(stdoutPipeRead, NULL, 0, NULL, &bytesAvail, NULL)) {
        std::cout << "Failed to call PeekNamedPipe" << std::endl;
    }
    if (bytesAvail) {
        CHAR buf[BUFSIZE];
        DWORD n;
        BOOL success = ReadFile(stdoutPipeRead, buf, BUFSIZE, &n, NULL);
        if (!success || n == 0) {
            std::cout << "Failed to call ReadFile" << std::endl;
        }
        std::cout << std::string(buf, buf + n);
    }
}
于 2015-11-03T08:29:25.650 に答える