我正在尝试执行命令行程序并在Windows上使用C ++获取输出。我最初使用_popen()
实现了这一点,但这会导致命令提示符窗口弹出如上所述here和here。
因此我实现了this answer和this article的混合,但遇到了ReadFile()
死锁的问题。在更多阅读之后,我添加了对PeakNamedPipe()
的调用,这导致读取循环执行无限而不是死锁(与我想要的相反,我宁愿等待exe退出),这让我相信我只是错误地设置了它。
以下代码是从原始代码(名称等)
稍加编辑的std::wstring args = "cmdApplication.exe with some args";
HANDLE readHandle;
HANDLE writeOutHandle;
HANDLE writeErrHandle;
HANDLE writeHandle;
if (!CreatePipe(&readHandle, &writeHandle, NULL, 0)) {
return false;
}
DuplicateHandle(GetCurrentProcess(), writeHandle, GetCurrentProcess(), &writeOutHandle, 0, true, DUPLICATE_SAME_ACCESS);
DuplicateHandle(GetCurrentProcess(), writeHandle, GetCurrentProcess(), &writeErrHandle, 0, true, DUPLICATE_SAME_ACCESS);
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
BOOL success = FALSE;
ZeroMemory( &processInfo, sizeof(PROCESS_INFORMATION) );
ZeroMemory( &startupInfo, sizeof(STARTUPINFO) );
startupInfo.cb = sizeof(STARTUPINFO);
startupInfo.hStdError = writeErrHandle;
startupInfo.hStdOutput = writeOutHandle;
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.dwFlags |= STARTF_USESTDHANDLES;
success = CreateProcess(NULL, (LPWSTR)args.c_str(), NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &processInfo);
DWORD read;
CHAR buffer[4096];
while(true) {
success = ReadFile(writeOutHandle, buffer, 4096, &read, NULL);//return false, GetLastError() returns ERROR_BROKEN_PIPE
if( ! success || read == 0 ) break;
}
CloseHandle(readHandle);
//Deal with the data in buffer
我可以运行这样的命令行应用程序,或者我应该运行cmd.exe并使用和输入管道来提供args?我实际上是否正确设置了管道?
编辑:在评论中来回一些之后,ReadFile()
不再死锁(保持写句柄阻止孩子完全退出)但不幸的是返回false,错误109: ERROR_BROKEN_PIPE很可能与this article有关(参见下文施法)。
如果正在使用匿名管道并且写入句柄已关闭,则当ReadFile尝试使用管道的相应读取句柄读取时,该函数返回FALSE,GetLastError返回ERROR_BROKEN_PIPE。
这引出了一个问题,如果我在管道打开时无法读取(由于ReadFile()
阻塞)并且当它退出时我无法读取(因为我收到错误说管道已经结束) ),我如何从管道中读取?