Microsoft example consider both program written from the same developer. In my case I was launching a generic program which output on stdout/stderr. I changed the Microsoft example in this way.
The following function run a generic externalProgram
with command line 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;
if (!CreatePipe(&m_hChildStd_OUT_Rd, &m_hChildStd_OUT_Wr, &saAttr, 0))
{
return HRESULT_FROM_WIN32(GetLastError());
}
if (!SetHandleInformation(m_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0))
{
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;
if (!CreateProcessA(NULL,
(TCHAR*)commandLine.c_str(),
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&si,
&pi)
)
{
return HRESULT_FROM_WIN32(GetLastError());
}
else
{
m_hreadDataFromExtProgram = CreateThread(0, 0, readDataFromExtProgram, NULL, 0, NULL);
}
return S_OK;
}
If CreateProcessA
succedeed, an external thread will be launched to asynchronousvly capture the output from the launched program. The code executed from the external thread is the following one:
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;
if (!bSuccess) break;
}
return 0;
}
I omitted any closing condition on all HANDLE
and threads involved in the code.