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
Cmake Unable to Determine Linker Language with C++
How to Write C++ Getters and Setters
C++11 Equivalent to Boost Shared_Mutex
What Are the Differences Between Overriding Virtual Functions and Hiding Non-Virtual Functions
Will Casting Around Sockaddr_Storage and Sockaddr_In Break Strict Aliasing
C++ Filehandling: Difference Between iOS::App and iOS::Ate
In C++11, Does 'I += ++I + 1' Exhibit Undefined Behavior
C++ Efficiently Calculating a Running Median
Pure Virtual Functions May Not Have an Inline Definition. Why
Use of the & Operator in C++ Function Signatures
Clearing Terminal in Linux with C++ Code
How Do Compilers Treat Variable Length Arrays
How to Check If the Input Is a Valid Integer Without Any Other Chars