使用Windows API在C ++中创建子进程时,可以允许从父对象继承句柄。在Microsoft示例"Creating a Child Process with Redirected Input and Output"中,将子进程'std in / out重定向到父进程创建的管道,有必要允许继承以使重定向管道可用。
我正在开发一个小型演示类,它启动外部可执行文件,读取输出,然后将其吐回调用者(将返回的输出记录到文件中)。我正在尝试建立一个超时功能,它只会阻止一段时间,然后再打电话给孩子TerminateProcess()
并继续生活。
但是,我发现通过允许句柄继承,子进程还有一个句柄(可用Process Explorer显示)到输出文件。我不希望子进程获取此句柄,但本例中的父(此演示类)也不知道句柄,因此我目前无法使用SetHandleInformation()
专门取消标记输出文件以排除它来自继承。
我确信必须有一种更好的方法来继承 ONLY 我想要的特定句柄,而不允许“毯子”继承传递意外和不需要的句柄。不幸的是,我一直无法找到解决方案,浏览了尽可能多的相关MSDN文章,并将Google自己置于沮丧状态。
至少,我需要做某些东西来删除子句中的句柄,而不必在demo类中使用这些句柄(它们被调用类使用,并且这个演示阶级没有明确的知识存在)。
任何更具选择性继承的解决方案?我特别感兴趣的是允许我专门声明要继承的句柄的解决方案,如果存在这样的解决方案,则不会继承所有未指定的句柄。
谢天谢地。
答案 0 :(得分:3)
如果输出文件句柄是由子进程继承的,那么这是因为父进程中的代码打开了文件,明确声明文件句柄应该是可继承的。它传递了CreateFile
lpSecurityAttributes
参数的值。 的句柄的默认状态是可继承的。
在我看来,你的流程创建类不应该试图猜测已经打开文件的调用者。
但是,如果您对具体处理新进程所需的内容有所了解,那么从Windows Vista开始,就有一种机制可以指定应该继承哪些句柄。当您准备致电CreateProcess
时,请使用STARTUPINFOEX
结构,而不是通常的STARTUPINFO
。它有一个lpAttributeList
成员。分配并初始化它,然后使用UpdateProcThreadAttribute
和PROC_THREAD_ATTRIBUTE_HANDLE_LIST
来设置要继承的句柄列表。所有句柄都需要是可继承的,当您调用bInheritHandles = true
时仍需要指定CreateProcess
。您还需要在EXTENDED_STARTUPINFO_PRESENT
参数中加入dwCreationFlags
。 Raymond 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。这是一个旧线程,但是仍然有很多意见,所以不要因为添加而杀死我:)