C语言 在Windows中,如何创建一个子进程并捕获它的stdin、stdout和stderr,而不复制任何可继承的句柄?

pvabu6sv  于 2024-01-06  发布在  Windows
关注(0)|答案(3)|浏览(157)

这个问题至少有三个部分,所以请原谅我:
1)ESPRProcess有一个参数bInheritHandles,它使子进程继承父进程中的所有可继承句柄。此选项必须设置为TRUE,以允许父进程在STARTUPINFO参数中为子进程指定stdin、stdout和stderr句柄。
2)在Win32中,当同一个文件有多个句柄打开时,删除和重命名文件可能会失败。
3)Microsoft CRT的open()函数将默认创建可继承的句柄。另外,默认创建的文件句柄会遇到上面的问题2。
这种神奇的组合产生了以下操作问题:库A调用open(),并且不希望随后的重命名和删除失败。在进程的其他地方,另一个库B正在调用bInheritHandles设置为TRUE的OpenProcess(捕获标准输入/输出/错误)临时创建重复的句柄。现在偶尔库A的文件操作失败。自然库A和B由不同的人维护。我也知道另一个使用open()的库A'也有类似的问题。
这个kb article讨论了一个相关的问题和解决方案。但是它仍然依赖于在父进程中将bInheritHandles设置为TRUE的情况下调用WebProcess,所以它没有解决这个问题。
我想知道其他人是否遇到过这个问题,是否有一个众所周知的解决方案?
上面的知识库文章本质上暗示了调用bInheritHandles设置为TRUE的进程是不合理的,所以我倾向于修复库B,使它永远不会这样做。我会通过以下方式做到这一点:
1.创建一个挂起的中间进程(理想情况下,使用rundll运行库B中的自定义入口点),并将bInheritHandles设置为NULL。
1.创建stdin/out/err管道,并将其正确的末端向上传输到中间进程。
1.以某种方式将复制的句柄传递给中间进程。
1.恢复中间过程。
1.在中间进程中,使用来自父进程的管道填写STARTUPINFO,并调用STARTUPINFO Process,同时将bInheritHandles设置为TRUE。
这是一个好的策略还是有更好的解决方案?你会如何推荐在步骤3中将复制的句柄传递给中间进程?rundll +自定义入口点是在步骤1中设置中间进程的可靠方法吗?

8xiog9wr

8xiog9wr1#

您可以使用PROC_THREAD_ATTRIBUTE_HANDLE_LIST扩展属性明确指定特定进程继承的句柄。
Raymond Chen的博客文章"Programmatically controlling which handles are inherited by new processes in Win32"包含了实现这一点的示例代码。
简短的版本:

  • InitializeProcThreadAttributeList()创建属性列表
  • UpdateProcThreadAttribute指定要继承的句柄
  • STARTUPINFOEX中的lpAttributeList成员集
  • EXTENDED_STARTUPINFO_PRESENT标志在对进程的调用中设置

需要Windows Vista,所以当这个问题最初被问到时可能没有解决OP问题,但是现在每个人都在使用Vista或更高版本,对吗?

iq3niunx

iq3niunx2#

如果您可以访问实际的文件句柄,则可以在调用SetHandleProcess()之前使用SetHandleInformation()删除HANDLE_FLAG_INHERIT标志。

xxhby3vn

xxhby3vn3#

您可以使用ZwQuerySystemInformation(SystemHandleInformation,...)ntdll.dll函数查找您的进程拥有的所有句柄,然后按照雷米的建议,查找每个句柄上的所有SetHandleInformation,以删除HANDLE_FLAG_INHERIT标志。

相关问题