views:

252

answers:

2

When creating a child process in C++ using Windows API, one can allow inheritance of handles from parent to child. In a Microsoft example "Creating a Child Process with Redirected Input and Output", redirecting a child process' std in/out to pipes created by the parent, it is necessary to allow inheritance for the redirection pipes to be usable.

I'm working on a small demo class that launches an external executable, reads the output, and then spits it back to the caller (who records the returned output to a file). I'm trying to build in a time-out feature, where it will only block for a certain amount of time before calling TerminateProcess() on the child and continuing on with life.

However, I've found that by allowing handle inheritance, the child process also has a handle (visible with Process Explorer) to the output file. I do not want the child process to obtain this handle, but the parent in this case (this demo class) is not aware of the handle either, so I cannot currently use SetHandleInformation() to unflag the output file specifically to exclude it from inheritance.

I am certain there must be a better way to inherit ONLY the specific handles that I want, without allowing "blanket" inheritance which passes unintended and undesired handles. Unfortunately I have been unable to find a solution, having browsed as many related MSDN articles as I can find, and having Googled myself into a state of discouragement.

At the very least, I need to do something to remove the handles from the child, without necessarily having those handles within the demo class (they're used by the calling class, and this demo class has no explicit knowledge of their existence).

Any solutions for more selective inheritance? I'm especially interested in the solution that allows me to specifically declare what handles to inherit, and all un-specified handles will not be inherited, if such a solution exists.

Thank you kindly.

+1  A: 

You can use SetHandleInformation to clear the HANDLE_FLAG_INHERIT bit on your output handle, this will prevent the child process from inheriting it.

If this flag is set, a child process created with the bInheritHandles parameter of CreateProcess set to TRUE will inherit the object handle.

John Knoeller
Thank you for your time and help. However, as I tried to explain in the OP, this demo class itself does not have a copy of the handle (it is owned by the caller of this method), and therefore I can not specifically unflag that specific handle using `SetHandleInformation`. Unless there is a quick way to enumerate all handles that would be inherited and unflag all but the specifically desired handles, I am not sure that it can be used to solve this. I am looking more for the "inherit only these explicit handles" approach, rather than "inherit all handles except this one".
KevenK
+1  A: 

If the output file handle is inherited by the child process, then that is because the code in the parent process the opened the file explicitly stated that the file handle should be inheritable. It passed a value for the lpSecurityAttributes parameter of CreateFile. The default state is for the handle to not be inheritable.

It seems to me that your process-creating class shouldn't try to second-guess its caller, who has already opened the file.

You could certainly try to enumerate all your program's open handles and set all their inheritance properties, but that seems to be beyond the scope of a function whose job is to create child processes. Let the code that creates the handles worry about whether they should be inheritable. The code creating new processes doesn't have enough information to make that judgment itself.

Rob Kennedy
While the sentiment of not second-guessing the original owner's intent is certainly a reasonable one to pass on, in this particular case I am familiar with how the caller works. The file is actually an `ofstream` opened quite generically with a "streamName.open("filename");" Although this seems to indicate that the default behavior for this std call is to create an inheritable handle, I still have a feeling that it should be possible to explicitly define which handles should be inherited when creating a child process. I am still hoping that this is possible, and that someone knows how.
KevenK
(continued from above). I ran out of space, but I also wanted to thank you for sharing your time and knowledge on the subject. I certainly appreciate the wisdom in allowing the creator to determine the inheritability of a handle if they had specifically wanted to share it. I do not disagree with the sentiment, only that I know in this case this is an unintended result. I want to believe that there's a "default none until specified" to counter the present "default all unless specified" setting. Wishful thinking on my part, perhaps! But thank you kindly for your time and wisdom.
KevenK
The only options you have when creating a process are to have the process inherit everything that has already been set to be inheritable, or to inherit nothing. Within that rule, you'll need to find the handles and set their inheritability afterward. If the file stream isn't creating the file with the properties you want, then call `CreateFile` yourself, and then wrap the handle using either `_open_osfhandle` and *fdstream.hpp*, or the Boost.Iostreams classes `file_descriptor` and `stream`.
Rob Kennedy