选择子进程继承的句柄

时间:2010-02-26 21:17:39

标签: c++ windows parent-child handle

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

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

但是,我发现通过允许句柄继承,子进程还有一个句柄(可用Process Explorer显示)到输出文件。我不希望子进程获取此句柄,但本例中的父(此演示类)也不知道句柄,因此我目前无法使用SetHandleInformation()专门取消标记输出文件以排除它来自继承。

我确信必须有一种更好的方法来继承 ONLY 我想要的特定句柄,而不允许“毯子”继承传递意外和不需要的句柄。不幸的是,我一直无法找到解决方案,浏览了尽可能多的相关MSDN文章,并将Google自己置于沮丧状态。

至少,我需要做某些东西来删除子句中的句柄,而不必在demo类中使用这些句柄(它们被调用类使用,并且这个演示阶级没有明确的知识存在)。

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

谢天谢地。

3 个答案:

答案 0 :(得分:3)

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

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

但是,如果您对具体处理新进程所需的内容有所了解,那么从Windows Vista开始,就有一种机制可以指定应该继承哪些句柄。当您准备致电CreateProcess时,请使用STARTUPINFOEX结构,而不是通常的STARTUPINFO。它有一个lpAttributeList成员。分配并初始化它,然后使用UpdateProcThreadAttributePROC_THREAD_ATTRIBUTE_HANDLE_LIST来设置要继承的句柄列表。所有句柄都需要是可继承的,当您调用bInheritHandles = true时仍需要指定CreateProcess。您还需要在EXTENDED_STARTUPINFO_PRESENT参数中加入dwCreationFlagsRaymond Chen demonstrated the technique in an article in 2011.

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

答案 1 :(得分:1)

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

  

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

答案 2 :(得分: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。这是一个旧线程,但是仍然有很多意见,所以不要因为添加而杀死我:)