파이프를 사용하여 명령 줄 실행 파일에서 표준 출력을 리디렉션하도록하고 있습니다. 불행히도 프로세스가 완료 될 때까지 출력이 없습니다. 실행 파일은 실행될 때 진행 상태를 출력하고 이것은 내가 파싱하고 싶은 것입니다. Windows : CreateProcess를 사용하여 리디렉션 된 Stdout의 버퍼링을 중지하는 방법
BOOL RunCmd(char *pCmd,
char *pWorkingDir,
int nWaitSecs,
BOOL fRegImport,
DWORD *pdwExitCode)
{
BOOL fSuccess = TRUE;
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES sFileSecurity;
ZeroMemory(&sFileSecurity, sizeof(sFileSecurity));
sFileSecurity.nLength = sizeof(sFileSecurity);
sFileSecurity.bInheritHandle = TRUE;
HANDLE hReadPipe = NULL;
HANDLE hWritePipe = NULL;
fSuccess = CreatePipe(&hReadPipe, &hWritePipe, &sFileSecurity, 0);
SetHandleInformation(hReadPipe, HANDLE_FLAG_INHERIT, 0);
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
si.hStdOutput = hWritePipe;
si.hStdError = hWritePipe;
si.wShowWindow = SW_HIDE;
int rc;
// Start the child process.
rc = CreateProcess(NULL, // No module name (use command line).
pCmd, // Command line.
NULL, // Process handle not inheritable.
NULL, // Thread handle not inheritable.
TRUE,
CREATE_NO_WINDOW,
NULL, // Use parent's environment block.
pWorkingDir, // Working folder
&si, // Pointer to STARTUPINFO structure.
&pi); // Pointer to PROCESS_INFORMATION structure.
if(! rc)
return FALSE;
// Wait until child process exits.
DWORD dwWaitResult;
DWORD dwTimeStart = ::GetTickCount();
DWORD dwTimeNow;
#define BUFSIZE 4096
DWORD dwRead = 0;
DWORD dwAvail;
CHAR chBuf[ BUFSIZE ];
BOOL bSuccess = TRUE;
for(;;)
{
dwTimeNow = ::GetTickCount();
dwWaitResult = ::WaitForSingleObject(pi.hProcess, ONE_SECOND);
dwRead = 0;
for(dwAvail = 0; PeekNamedPipe(hReadPipe, 0, 0, 0, &dwAvail, 0) && dwAvail; dwAvail = 0)
{
dwRead = 0;
ReadFile(hReadPipe, chBuf, min(BUFSIZE, dwAvail), &dwRead, NULL);
if(dwRead > 0)
{
FILE *op = fopen("c:\\REDIR.OUT", "a");
if(op)
{
fwrite(chBuf, 1, dwRead, op);
fclose(op);
}
}
}
if(dwWaitResult == WAIT_OBJECT_0)
{
DWORD dwExitCode;
GetExitCodeProcess(pi.hProcess, &dwExitCode);
if(pdwExitCode)
(*pdwExitCode) = dwExitCode;
break;
}
if(dwWaitResult == WAIT_TIMEOUT)
{
if(dwTimeNow - dwTimeStart < (DWORD)(ONE_SECOND * nWaitSecs))
continue;
else
{
fSuccess = FALSE;
break;
}
}
fSuccess = FALSE;
break;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hReadPipe);
CloseHandle(hWritePipe);
return fSuccess;
}
PeekNamedPipe() 호출
매초 호출하고, 처리가 완료 될 때까지 dwAvail마다 제로이다.프로세스의 출력을 더 빨리 얻으려면 어떻게해야합니까? 콘솔에서 프로세스를 실행할 때 진행 상황을 볼 수 있습니다. 프로세스는 출력에서 "\ r"을 사용하여 같은 줄의 시작 부분에 백분율을 표시합니다.
버퍼링은 OS가 아닌 다른 앱에 있습니다. 버퍼링을 사용하지 않도록 설정하려면 실행중인 프로세스를 수정해야합니다. –
@ RaymondChen 고마워요. 그게 내 가장 큰 두려움이었습니다. 우리는 그 근원이 없습니다. 생각해 보니 Visual Studio "외부 도구"로도 실행했을 때 결과를 버퍼링하는 것으로 나타났습니다. CMD.exe가 모든 진행 상태 업데이트를 표시 할 수 있다면 래퍼 프로그램이 동일한 작업을 수행 할 수 있다고 생각할 수 있습니다. – SparkyNZ
@RaymondChen 그래, 다음 링크에서 문제를 설명합니다 : https://support.microsoft.com/en-nz/kb/190351 – SparkyNZ