パイプを使用して、コマンドライン実行可能ファイルからリダイレクトされたstdout出力を取得しています。残念ながら、プロセスが完了するまでは出力がありません。実行可能ファイルは実行中の進行状況を出力し、これは私が解析したいものです。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