How to Redirect Output to a File with Createprocess

How do I redirect output to a file with CreateProcess?

You can't use stdout redirection in the command line passed to CreateProcess. To redirect stdout you need to specify a file handle for the output in the STARTUPINFO structure.

You are also making another, more subtle, mistake. The second parameter, lpCommandLine must point to writeable memory because CreateProcess overwrites the buffer. If you happen to be using the ANSI version of the function then you will get away with this, but not for the Unicode version.

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.

CreateProcess and redirecting output

Close the out_write and in_read handles after calling CreateProcess. Otherwise ReadFile on out_read will block when the pipe is empty because there's still a potential writer even after the child has exited -- the out_write handle in the current process.

Also, as noted by Harry Johnston in a comment, waiting for the process to exit before reading from the pipe can potentially cause a deadlock. The child will block on WriteFile if the pipe fills up.

How to redirect large amount of output from command executed by CreateProcess?

Create a file handle for the redirection. That's what your cmd script does. That redirects to a file named 'MYDB.bak'.

So, call CreateFile to create a file with that name, and assign the handle returned as StartupInfo.hStdOutput. When the external process has finished, call CloseHandle on the file handle to close the file. You'll need to decide what to do about the standard error handle. One common choice is to merge it with standard output. Assign the same handle to both hStdOutput and hStdError.

Your code is assigning standard handles, but not asking that the external process uses them. You need to include STARTF_USESTDHANDLES in StartupInfo.dwFlags.

The call to CreateFile will look like this:

StdOutFileHandle := CreateFile(
'MYDB.bak',
GENERIC_WRITE,
FILE_SHARE_READ,
nil,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
0
);

Check that the value returned by CreateFile is not equal to INVALID_HANDLE_VALUE.

As I mentioned in your previous question, you need the external process to inherit the file handle that you pass it. If you don't allow inheritance of handles then the external process cannot use the handle that you pass it. So pass True for the bInheritHandles parameter of CreateProcess.

The file handle created by CreateFile is not, by default inheritable. You can either pass security attributes that make it inheritable. Or you can set it explicitly after you have created. The latter looks like this:

Win32Check(SetHandleInformation(StdOutFileHandle, HANDLE_FLAG_INHERIT, 1));

Examples of the former (in the context of pipes) can be seen in my answer here: How to redirect binary gbak output to a Delphi stream?

The code that mentions StdOutPipeWrite all needs to be deleted. It cannot work at the moment because you are not initializing the handle.

You should make good use of try/finally to ensure that you don't leak any handles even in the face of exceptions.

Finally, your code contains a lot of errors, and little error checking. I suggest that you read and re-read the documentation for CreateProcess. Also have a good read of this example on MSDN: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682499.aspx. Although it uses pipes, the principals are the same. Do exactly the same, but instead of pipes use the handle returned by the call to CreateProcess.

CreateProcess and capture stdout

The short answer is to create an anonymous pipe, setting the hStdOut/hStdErr and dwFlag members of the STARTUPINFO structure accordingly, and have CreateProcess() inherit the handle for the writing end of the pipe. Don't forget to close your writing handle of your pipe, then you can read from the reading handle of the pipe in a loop until it fails with an ERROR_BROKEN_PIPE error.

MSDN provides a detailed example of this:

Creating a Child Process with Redirected Input and Output

You are not the first person to do this, there should be plenty of example code and duplicate questions here on StackOverflow.

Windows CreateProcess and output redirection

As pointed out in the comment, handles must be inheritable, which means replacing the CreatePipe like this :

SECURITY_ATTRIBUTES pipeAttrib;
memset(&pipeAttrib, 0, sizeof(pipeAttrib));

pipeAttrib.nLength = sizeof(SECURITY_ATTRIBUTES);
pipeAttrib.bInheritHandle = NULL;
pipeAttrib.bInheritHandle = TRUE;

if (!CreatePipe(&StdOutHandles[0], &StdOutHandles[1],&pipeAttrib, 4096)) {
printf("Create pipe error %d\n", GetLastError());
return NULL;
}

And setting CreateProcess 5th parameter (bInheritHandles) to TRUE instead of FALSE.

Unable to redirect standard output using CreateProcess

your hfile is not inheritable - you need use SECURITY_ATTRIBUTES in call CreateFile

SECURITY_ATTRIBUTES sa = { sizeof(sa), 0, TRUE };
HANDLE hfile = CreateFile("output.txt", GENERIC_WRITE, 0, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

How do I redirect output to a file with CreateProcess?

You can't use stdout redirection in the command line passed to CreateProcess. To redirect stdout you need to specify a file handle for the output in the STARTUPINFO structure.

You are also making another, more subtle, mistake. The second parameter, lpCommandLine must point to writeable memory because CreateProcess overwrites the buffer. If you happen to be using the ANSI version of the function then you will get away with this, but not for the Unicode version.

The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.



Related Topics



Leave a reply



Submit