使用CreateProcess运行另一个程序时,捕获标准输出的建议方法是什么?也就是说,将第二个程序打印到stdout中的任何内容,并在第一个程序可以分析它的数组中结束它?
这两个程序都是用C语言编写的直接Win32程序,没有花哨的东西。
答案 0 :(得分:2)
Microsoft 示例考虑由同一开发人员编写的两个程序。就我而言,我正在启动一个在 stdout/stderr 上输出的通用程序。我以这种方式更改了 Microsoft 示例。
以下函数使用命令行 externalProgram
运行通用 arguments
:
HANDLE m_hChildStd_OUT_Rd = NULL;
HANDLE m_hChildStd_OUT_Wr = NULL;
HANDLE m_hreadDataFromExtProgram = NULL;
HRESULT RunExternalProgram(std::string externalProgram, std::string arguments)
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
SECURITY_ATTRIBUTES saAttr;
ZeroMemory(&saAttr, sizeof(saAttr));
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// Create a pipe for the child process's STDOUT.
if (!CreatePipe(&m_hChildStd_OUT_Rd, &m_hChildStd_OUT_Wr, &saAttr, 0))
{
// log error
return HRESULT_FROM_WIN32(GetLastError());
}
// Ensure the read handle to the pipe for STDOUT is not inherited.
if (!SetHandleInformation(m_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
{
// log error
return HRESULT_FROM_WIN32(GetLastError());
}
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.hStdError = m_hChildStd_OUT_Wr;
si.hStdOutput = m_hChildStd_OUT_Wr;
si.dwFlags |= STARTF_USESTDHANDLES;
ZeroMemory(&pi, sizeof(pi));
std::string commandLine = extProgram + " " + arguments;
// Start the child process.
if (!CreateProcessA(NULL, // No module name (use command line)
(TCHAR*)commandLine.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // Set handle inheritance
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
m_hreadDataFromExtProgram = CreateThread(0, 0, readDataFromExtProgram, NULL, 0, NULL);
}
return S_OK;
}
如果 CreateProcessA
成功,将启动一个外部线程以异步捕获已启动程序的输出。从外线程执行的代码如下:
DWORD __stdcall readDataFromExtProgram(void * argh)
{
DWORD dwRead;
CHAR chBuf[BUFSIZE];
BOOL bSuccess = FALSE;
for (;;)
{
bSuccess = ReadFile(m_hChildStd_OUT_Rd, chBuf, BUFSIZE, &dwRead, NULL);
if (!bSuccess || dwRead == 0) continue;
// Log chBuf
if (!bSuccess) break;
}
return 0;
}
我省略了代码中涉及的所有 HANDLE
和线程的任何结束条件。
答案 1 :(得分:1)
简短的回答是创建一个匿名管道,相应地设置hStdOut
结构的hStdErr
/ dwFlag
和STARTUPINFO
成员,并CreateProcess()
继承管道写入端的句柄。不要忘记关闭管道的写入句柄,然后您可以循环读取管道的读取句柄,直到它因ERROR_BROKEN_PIPE
错误而失败。
MSDN提供了一个详细的例子:
Creating a Child Process with Redirected Input and Output
你不是第一个这样做的人,StackOverflow上应该有大量的示例代码和重复的问题。
答案 2 :(得分:1)
Remy Lebeau提到的MSDN示例不适用于我,它永久挂在WriteToPipe()调用中。为了简化起见,我将子进程替换为“ ping 127.0.0.1”,并注释了WriteToPipe()调用。现在,我可以捕获输出了。