Win32 , C++

Pipe 로 표준 출력 잡기

김모작자 2012. 8. 27. 14:42

ffmpeg 등 command line 툴의 콘솔 출력을 잡기 위해선 pipe 를 이용하여
std-in, std-out, std-err 를 redirection 해야한다.

redirection 은 fprintf(stdout)..., printf, fgets  등의 표준 I/O 의 목적지를 화면이 아닌 모(母) 프로그램이 받도록 도와준다.

Win32 함수로 구현하기 위해선 CreatePipe, Duplicate, ReadFile, WriteFile, CloseHandle 함수를 사용해야 한다.
여러 프로그램을 pipe 로 연결시킨 경우 각각의 프로세스를 만들고 앞 프로세스의 output 을 다음 프로세스의 input 에 수동으로 넣어줘야 한다. 난 당연히 자동으로 되겠지 했으나 왜 그런지 에러만 났을 뿐이다.

  CreatePipe(&ReadFromInput, &WriteToInput, nullptr, PIPE_LENGTH);  
  CreatePipe(&ReadFromOutput, &WriteToOutput, nullptr, PIPE_LENGTH);  
  CreatePipe(&ReadFromError, &WriteToError, nullptr, PIPE_LENGTH);

  DuplicateHandle( GetCurrentProcess(), ReadFromInput, GetCurrentProcess(), &exec.hInput, 0, TRUE, DUPLICATE_SAME_ACCESS);   
  DuplicateHandle( GetCurrentProcess(), WriteToOutput, GetCurrentProcess(), &exec.hOutput, 0, TRUE, DUPLICATE_SAME_ACCESS);  
  DuplicateHandle( GetCurrentProcess(), WriteToError, GetCurrentProcess(), &exec.hError, 0, TRUE, DUPLICATE_SAME_ACCESS);   
  
  DuplicateHandle( GetCurrentProcess(), WriteToInput, GetCurrentProcess(), &exec.hWriteToFFMPEG, 0, FALSE, DUPLICATE_SAME_ACCESS); 
  DuplicateHandle( GetCurrentProcess(), ReadFromOutput, GetCurrentProcess(), &exec.hReadFromFFMPEG, 0, FALSE, DUPLICATE_SAME_ACCESS); 
  DuplicateHandle( GetCurrentProcess(), ReadFromError, GetCurrentProcess(), &exec.hReadFromFFMPEGError, 0, FALSE, DUPLICATE_SAME_ACCESS); 

  CloseHandle( WriteToInput ); WriteToInput = NULL;
  CloseHandle( ReadFromOutput ); ReadFromOutput = NULL;
  CloseHandle (ReadFromError); ReadFromError = NULL;

  PROCESS_INFORMATION pi;
  ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

  STARTUPINFO si;
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);
  si.dwFlags = STARTF_USESTDHANDLES;
  si.hStdInput = exec.hInput;
  si.hStdOutput = exec.hOutput;
  si.hStdError = exec.hError;

  SetLastError(0);
  
  TCHAR CommandLine[10240];
  _tcscpy_s(CommandLine, cei.CommandLine);
  ...

  launch_ok = CreateProcess(nullptr, CommandLine, nullptr, nullptr, TRUE, CREATE_NO_WINDOW, (LPVOID)my_env_param, nullptr, &si, &pi);