在Windows中,如何创建子进程并捕获其stdin,stdout和stderr,而无需复制任何可继承的句柄?

这个问题至少有三个部分,所以请耐心等待:

1)CreateProcess有一个参数bInheritHandles,它使子进程继承父进程中的所有可继承句柄.必须将此选项设置为TRUE,以允许父级在STARTUPINFO参数中为子级指定stdin,stdout和stderr句柄.

2)在Win32中,当同一个文件有多个句柄打开时,删除和重命名文件可能会失败.

3)Microsoft CRT的open()函数默认创建可继承的句柄.此外,默认情况下创建的文件句柄会遇到上面的问题2.

这种神奇的组合会产生以下操作问题:库A调用open()并且不希望后续的重命名和删除失败.在此过程中的另一个库B调用CreateProcess,并将bInheritHandles设置为TRUE(以捕获stdin / out / err),暂时创建重复句柄.现在偶尔库A的文件操作失败了.自然地,图书馆A和B由不同的人维护.我也知道另一个使用open()并且遇到类似问题的库A’.

这篇kb article讨论了一个相关的问题和解决方案.但是它仍然依赖于在父进程中将bInheritHandles设置为TRUE来调用CreateProcess,因此它无法解决此问题.

我想知道其他人是否遇到过这个问题,是否有一个众所周知的解决方案?

上面的kb文章基本上暗示调用带有bInheritHandles设置为TRUE的CreateProcess很生,所以我倾向于修复库B,使它永远不会这样做.我会这样做:

>创建一个暂停的中间过程(理想情况下,通过使用rundll在库B中运行自定义入口点),并将bInheritHandles设置为FALSE.
>创建stdin / out / err管道并将这些管道的正确结尾复制到中间过程.
>以某种方式将欺骗手柄传递给中间过程.
>恢复中间过程.
>从中间过程使用父项中的管道填充STARTUPINFO,并将bInheritHandles设置为TRUE调用CreateProcess.

这是一个好策略还是有更好的解决方案?
您如何建议在步骤3中将欺骗手柄传递给中间过程?
rundll自定义入口点是在步骤1中设置中间过程的可靠方法吗?

最佳答案 如果您有权访问实际的文件句柄,则可以在调用CreateProcess()之前使用SetHandleInformation()删除HANDLE_FLAG_INHERIT标志.

点赞