2010-07-24 2 views
6

Visual Studio에서 출력 창이나 다른 도구 창에서 수행하는 작업과 비슷합니다. 프로세스 A에서 다른 프로세스 B를 시작하고 stdout/stderr 출력을 캡처합니다.대기 시간없이 Win32에서 다른 프로세스의 stdout을 캡처하는 방법은 무엇입니까?

지금까지 CreatePipe()으로 작업했는데 어떤 이유로 B 출력이 작성되면 B 출력에 도달하지 않습니다. 어떤 종류의 버퍼가 채워지는 것처럼 동작하며, 버퍼가 가득 차면 모든 버퍼 내용이 한 번에 A에 도착합니다. 나는 뭔가를 출력하고 나중에 직접 fflush(stdout)을 수행하는 자체 테스트 프로그램을 작성했습니다. 그런 다음 출력물이 A에 직접 도착합니다. 그런 식으로 사용하려는 모든 B 프로세스의 코드를 변경할 수는 없습니다. A에서 파이프를 플러시하려고해도 작동하지 않습니다.

어떻게 작동하나요?

내 초기화 코드뿐만 아니라 소모 코드 :

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

err = CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &sa, stdouthistory); 
if (err == 0) 
    return 1; 
err = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd, 
         GetCurrentProcess(), &hChildStdoutRdDup , 0, 
         FALSE, 
         DUPLICATE_SAME_ACCESS); 
if (err == 0) 
    return 3; 
CloseHandle(hChildStdoutRd); 

DWORD a, b, c; 
a = PIPE_READMODE_BYTE | PIPE_NOWAIT; 
b = 0; 
c = 0; 
SetNamedPipeHandleState(hChildStdoutRdDup, &a, &b, &c); 

err = CreatePipe(&hChildStdinRd, &hChildStdinWr, &sa, stdinhistory); 
if (err == 0) 
    return 1; 
err = DuplicateHandle(GetCurrentProcess(), hChildStdinWr, 
         GetCurrentProcess(), &hChildStdinWrDup , 0, 
         FALSE, 
         DUPLICATE_SAME_ACCESS); 
if (err == 0) 
    return 4; 
CloseHandle(hChildStdinWr); 

a = PIPE_READMODE_BYTE | PIPE_NOWAIT; 
b = 0; 
c = 0; 

ZeroMemory(&si,sizeof(STARTUPINFO)); 
si.cb = sizeof(STARTUPINFO); 
si.dwFlags = STARTF_USESTDHANDLES; 
si.wShowWindow = SW_SHOW; 

si.hStdOutput = hChildStdoutWr; 
si.hStdError = hChildStdoutWr; 
si.hStdInput = hChildStdinRd; 

ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); 

err = CreateProcess(0, this->cmdline, 0, 0, true, CREATE_NO_WINDOW, 0, 0, &si, &pi); 
if (err == 0) 
    return 4; 

소비 :

DWORD avail; 
unsigned int ofs = 0; 
if (PeekNamedPipe(hChildStdoutRdDup, NULL, 0, NULL, &avail, NULL)) 
{ 
    if (avail != 0) 
    { 
     int err = ReadFile(hChildStdoutRdDup, s + ofs, slen, &threadbuffern, 0); 
          // Consume ... 
    } 
} 

편집 : Continuously read from STDOUT of external process in Ruby : 난 그냥이 질문을 발견했다. 루비의 맥락에서와 같은 문제입니다. 슬프게도 해결책은 Ruby 라이브러리를 사용하는 것입니다. 그 도서관은 어떻게합니까? Win32/C++에서 동등한 것은 무엇입니까?

+1

연결된 스레드는 * nix 솔루션입니다. Win32와 비슷한 것은 없습니다. –

+0

유닉스에만 관련이 있다는 것을 어떻게 알 수 있습니까? 또한 잘 닫을 수있는 프로그램이 Windows에 있습니다./ – marc40000

답변

3

당신은 그렇게 할 수 없습니다. 문제가있는 프로세스에서 출력이 플러시되지 않은 경우 실제로는 처음에 stdout에 기록되지 않습니다. 즉, OS는 아직 대상 프로세스의 데이터를 실제로 가져 오지 않았습니다.

이것은 파이프에 고유 한 대기 시간이 아니며 모니터링하는 프로그램이 실제 파이프에 아직 기록하지 않은 것입니다.

명령 프롬프트에서 사용중인 것과 동일한 파이프 솔루션을 사용하기 때문에 해당 프로그램을 실행할 때 명령 프롬프트에 똑같은 동작이 발생합니다. 그렇지 않은 경우 문제의 프로그램이 콘솔 핸들이 아닌 파일 핸들에 쓰고 있음을 감지하고 추가 버퍼링을 수행하고 있기 때문입니다.

+0

흠, 어떻게 감지합니까? 그 문제를 해결할 수 있습니까? 제가 게시 한 다른 질문에 대한 링크에있는 루비 라이브러리는 그렇게 할 수있을 것 같습니다. – marc40000

+0

@marc : 1. 루비 라이브러리가 Windows에 없습니다. 2. 루비 라이브러리는 다른 프로그램을 제어 할 수도 있고하지 않을 수도 있습니다. Ruby에서 실제 라이브러리가 필요한 이유는 루비의 제한 때문이며 제어 된 애플리케이션의 제한이 아니기 때문입니다. 따라서 도서관은 그것을 고칠 수있었습니다. –