May 11th, 2026
likemind blown3 reactions

Additional notes on controlling which handles are inherited by Create­Process

Some time ago, I wrote about programmatically controlling which handles are inherited by new processes in Win32 by using the PROC_THREAD_ATTRIBUTE_HANDLE_LIST to limit exactly which handles are inherited. That way, when you create a new process, you have precise control over which handles get inherited and don’t accidentally inherit handles created by unrelated components in your process.

A collegue of mine pointed out that you still have the reverse problem: Since handles must be marked as inheritable for them to participate in PROC_THREAD_ATTRIBUTE_HANDLE_LIST, if another thread calls Create­Process with bInheritHandles = TRUE but without using PROC_THREAD_ATTRIBUTE_HANDLE_LIST, then they will accidentally inherit all of your handles.

This problem could have been avoided if the PROC_THREAD_ATTRIBUTE_HANDLE_LIST allowed you to include non-inheritable handles, in which case they would be non-inheritable by normal Create­Process but inheritable if explicitly opted back in. But alas, that’s not how it was designed.

Instead, you can create a helper process. All this helper process does is wait for the main process to exit, and then exit itself.

WaitForSingleObject(hMainProcess, INFINITE);
ExitProcess(0);

This process doesn’t sound like it’s doing anything useful, and it’s not. But what makes it useful is not what it’s doing but rather what is done to it.

The components in the main process create their handles as non-inheritable. When they wants to create a process with specific inherited handles, they duplicate the desired handles into the helper process (as inheritable), and then build a PROC_THREAD_ATTRIBUTE_HANDLE_LIST that lists those duplicates as handles to inherit. They also use the PROC_THREAD_ATTRIBUTE_PARENT_PROCESS to specify that the helper process is the parent process that the handles should be inherited from. Then they pass those thread attributes to Create­Process, and the new process will inherit exactly those handles. Then they clean up by closing the handles in the helper process with the help of Duplicate­Handle and DUPLICATE_CLOSE_SOURCE.

Notice that multiple threads can simultaneously be operating on the helper process in this way, so you need only one helper process to service all your handle-inheritance-control needs.

This avoids the accidental inheritance problem because the handles that belong to the components in the main process are still marked non-inheritable, so any other code in the main process that does a Create­Process will not inherit them.

Topics

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

5 comments

Discussion is closed. Login to edit/delete existing comments.

Sort by :
  • Joshua Hudson

    Assuming the parent process handle is passed via inherit handle, anybody wanna see this binary in 1KB? It might fit without but implementing get parent process on Windows the documented way is obnoxious.

    • LB · Edited

      You don’t need to fuss with passing any handles. Just make an executable that sleeps forever and put it in a job object. If the parent process ends for any reason, the job object will terminate the sleeping process. If you are worried about click-happy users running the sleeper process independently, you can have it check if it’s in a job or not and exit if not.

  • Daniel Chýlek

    None of the links in the referenced blog post work anymore. I despise Microsoft breaking tens of thousands of URLs and not providing redirects.

    • alan robinson

      Just another signature of how they treat this as idle entertainment instead of “the documentation that microsoft forgot to write” (that happens to be quite entertaining, too).

      Or you know, EnshiXXXXXXX.

    • LB

      Wayback Machine has an archive of the whole blog dated around January 2019, if you navigate the archives through there you can view all the blog entries and comments too, and sometimes the links even work. Not the most pleasant experience, but it’s something. Broken links usually have the date in the link as well, which usually enough to go track down the source. Other blogs linked to can usually be searched by title or author and you can find non-wayback-machine archives of them as well, sometimes with anonymized comments.