An obscure detail that is hard to see in .NET is the bInheritHandles CreateProcess () argument, a nasty little unixism that sneaked into winapi. Determining the correct value for this argument is very difficult to understand, you need to learn a lot about the process that you are starting, and it scales very poorly, this is an all-or-nothing option. Raymond Chen has a blog post that talks about ugly corner cases and what they did in Windows version 6.0 to solve the problem.
Otherwise, it is a solution that can be used in .NET. First of all, because it still supports older versions of Windows up to .NET 4.5. And it would be quite difficult to use. Accordingly, the ProcessStartInfo class does not have a property that allows you to explicitly control the value of the bInheritHandles argument, Process.Start () always passes TRUE. This is what "as long as we do not pass through the first-class handlers," refers to.
Another detail is that the descriptor that the child process inherits is a separate descriptor different from the descriptor of the parent process. Therefore, a total of two CloseHandle calls are required to destroy a system object. Or, to put it another way, both the parent and the child must stop using the object. This means that the "OS considers the parent and child descriptors to be different" comment refers to.
The main function of CreatePipe () winapi, which is used to create an anonymous channel, returns two descriptors, one for reading and one for writing. Depending on the direction of the pipe, the parent (aka server) and one child process (aka client) should be used. These descriptors are inherited handles, so after starting the child process, four CloseHandle calls are required to destroy the pipe object.
It is unpleasant. The .NET wrapper can do something with the server handle. It calls DuplicateHandle () to make a copy of the server-side descriptor, passing FALSE for the bInheritHandle argument. Then closes the original pen. Well, the child process will no longer inherit the server descriptor, so now only three calls to CloseHandle are required.
The same trick, however, cannot work for the channel handle that the child process should use. In the end, the intention is to inherit the handle so that it can return to the server. This is why you should do this explicitly after learning that the child process has been started properly. After calling the DisposeLocalCopyOfClientHandle () method, now only two calls to CloseHandle are required.
Calling CloseHandle on the client side is quite simple; it does this by calling Close or Dispose on AnonymousPipeClientStream. Or, flipping over with an unhandled exception that causes the process to crash, the OS then takes care of closing the handle. Now there is only one call to CloseHandle.
One to go, it is harder on the server side. He only knows to close / delete his anonymous protocol when he receives a notification that the child process is no longer using it. Scary quotes around the "notification", there is no event that reports this. The correct way is for the child process to send an explicit "goodbye" message so that the server knows that you need to call Close. Not quite correct, but not unusual way is that the child did not say goodbye beautifully, then the server can only know that he no longer exists from the exception that he receives when he continues to use this channel.
Which key, you get only an exception when the OS sees that the server is trying to use this channel and there are no other handles on the other side. Or, in other words, if you forget to call DisposeLocalCopyOfClientHandle (), then you will not get an exception. Not good.