Tuesday, July 12, 2005

Windows: How to capture stdout from a spawned child process

The below code is similar to my last post. However, it *does* work on Windows while the previous code only works on Unix.

std::string command = ...;

ACE_Process_Options opt;

// The child process to spawn.

// Define the two handles for the pipe,
// fd[0] will be used for stdin
// fd[1] will be used for stdout.

// Create a pipe from the two file handles.
// Pipe between stdin and stdout.
// fd[0] <-> fd[1]
if (ACE_OS::pipe(fd) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "pipe failed"));

// Set the stdin and stdout of the process to our file handles.
// fd[0] is used for stdin, fd[1] is used for stdout.
opt.set_handles(fd[0] /*stdin*/, fd[1] /*stdout*/);

// Spawn the child process.
ACE_Process proc;
if (proc.spawn(opt) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "spawn failed"));

// Wait for the process to finish.
ACE_exitcode exitcode = 0;

// After fork:
// fd[0] <-> fd[1] child
// fd'[0] <-> fd'[1] parent

// Need to close parent stdout or parent will be trying to read from it forever.
// With stdout closed parent will get EOF from the child so that the parent
// will know the child is done.
if (ACE_OS::close(fd[1]) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "close stdout"));

// After close:
// fd[0] <-> fd[1] child
// fd'[0] <-> parent
// which leaves our (parent) stdin piped to child's stdout

// set_handles() dups the handles, so make sure they are released.

// Read from parent's stdin, which is connected
// to the child's stdout.
std::string child_stdout;
const size_t BUFFSIZE = 1024;
char buf[BUFFSIZE + 1];
ssize_t n = 0;
while ((n = ACE_OS::read(fd[0], buf, BUFFSIZE)) > 0) {
buf[n] = 0;
child_stdout.append(buf, n);

// Close stdin.
if (ACE_OS::close(fd[0]) == -1)
ACE_DEBUG ((LM_ERROR, "%p\n", "close stdin"));


Anonymous said...

I tried this on XP, using "dir" as the command to spawn. The spawn fails, and the program outputs :

spawn failed: No such file or directory

Any idea what could be wrong?

Kevin Heifner said...

I just tried dir on my XP Pro machine and it worked fine. I'm tested with TAO (ACE) 1.3a_p10 (5.3a_p10). What version are you using?