8

使用 Windows API 在 C++ 中创建子进程时,可以允许从父进程到子进程继承句柄。在 Microsoft 示例“Creating a Child Process with Redirected Input and Output”中,将子进程的 std in/out 重定向到由父进程创建的管道,必须允许继承以使重定向管道可用。

我正在开发一个小型演示类,它启动一个外部可执行文件,读取输出,然后将其吐回给调用者(后者将返回的输出记录到文件中)。TerminateProcess()我正在尝试构建一个超时功能,它只会在调用孩子并继续生活之前阻塞一段时间。

但是,我发现通过允许句柄继承,子进程还有一个到输出文件的句柄(使用Process Explorer可见)。我不希望子进程获得这个句柄,但是在这种情况下,父进程(这个演示类)也不知道这个句柄,所以我目前不能使用SetHandleInformation()专门取消标记输出文件以将其从继承中排除。

我确信必须有更好的方法来继承我想要的特定句柄,而不允许传递意外和不希望的句柄的“一揽子”继承。不幸的是,我浏览了尽可能多的相关 MSDN 文章,并在谷歌上搜索到了自己的沮丧状态,但我一直无法找到解决方案。

至少,我需要做一些事情来从孩子身上删除句柄,而不必在演示类中拥有这些句柄(它们由调用类使用,并且这个演示类没有明确知道它们的存在)。

更多选择性继承的任何解决方案?我对允许我专门声明要继承哪些句柄的解决方案特别感兴趣,如果存在这样的解决方案,所有未指定的句柄都不会被继承。

非常感谢你。

4

3 回答 3

4

如果输出文件句柄被子进程继承,那是因为打开文件的父进程中的代码明确声明文件句柄应该是可继承的。lpSecurityAttributes它为 的参数传递了一个值CreateFile。默认状态是句柄不可继承。

在我看来,您的进程创建类不应该尝试猜测已经打开文件的调用者。

但是,如果您对新进程需要哪些句柄有专门的了解,那么从 Windows Vista 开始,有一种机制可以指定应该继承哪些句柄。当您准备调用时CreateProcess,请使用STARTUPINFOEX结构而不是通常的结构STARTUPINFO。它有一个lpAttributeList成员。分配并初始化它,然后使用UpdateProcThreadAttributewithPROC_THREAD_ATTRIBUTE_HANDLE_LIST设置要继承的句柄列表。所有的句柄都需要是可继承的,你仍然需要bInheritHandles = TRUE在调用CreateProcess. 您还需要包含EXTENDED_STARTUPINFO_PRESENTdwCreationFlags参数中。Raymond Chen 在 2011 年的一篇文章中展示了该技术。

如果您无法使用该附加功能,那么您当然可以尝试枚举所有程序的打开句柄并使用 设置它们的所有继承属性SetHandleInformation,但这似乎超出了创建子进程的函数的范围。让创建句柄的代码担心它们是否应该是可继承的。

于 2010-02-26T21:59:22.030 回答
1

您可以使用SetHandleInformation清除HANDLE_FLAG_INHERIT输出句柄上的位,这将防止子进程继承它。

如果设置了此标志,则使用 CreateProcess 的 bInheritHandles 参数设置为 TRUE 创建的子进程将继承对象句柄。

于 2010-02-26T21:22:39.797 回答
0

值得注意的是,使用 SetHandleInformation 很容易出现竞争条件,以防多个线程创建进程。这是一个测试序列:

thread 1: HANDLE h = ::CreateFile(..., lpSecurityAttributes = NULL, ...);
thread 2: ::CreateProcess(..., inherit_handles=TRUE, ...);
thread 1: ::SetHandleInformation (h, HANDLE_FLAG_INHERIT, FALSE);
// the above line is useless, because child process created by thread 2 has already inherited the handle

正确的方法是在句柄创建期间始终指定句柄继承,例如:

SECURITY_ATTRIBUTES sa = { 0 };
sa.bInheritHandles = FALSE;
HANDLE h = ::CreateFile(..., lpSecurityAttributes = &sa, ...);

请注意,Microsoft 的 fopen() 实现有一个特殊的模式值“N”,它禁用句柄继承。

P.S. This is an old thread, but still has a lot of views, so don't kill me for adding to it :)

于 2020-09-14T18:44:25.467 回答