这个问题至少有三个部分,所以请耐心等待:
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 由不同的人维护。我还知道另一个库 A' 使用 open() 并遇到类似问题。
这篇知识库文章讨论了一个相关的问题和解决方案。但是它仍然依赖于在父进程中调用 CreateProcess 并将 bInheritHandles 设置为 TRUE,所以它不能解决这个问题。
我想知道其他人是否遇到过这个问题,是否没有众所周知的解决方案?
上面的 kb 文章基本上暗示在将 bInheritHandles 设置为 TRUE 的情况下调用 CreateProcess 是不明智的,所以我倾向于修复库 B,使其永远不会这样做。我会这样做:
这是一个好的策略还是有更好的解决方案?您建议如何将被欺骗的句柄传递给步骤 3 中的中间过程?rundll + 自定义入口点是在步骤 1 中设置中间过程的可靠方法吗?
您可以使用PROC_THREAD_ATTRIBUTE_HANDLE_LIST扩展属性来明确指定特定进程继承的句柄。
Raymond Chen 的博客文章“以编程方式控制 Win32 中的新进程继承哪些句柄”包含执行此操作的示例代码。
简短版本:
InitializeProcThreadAttributeList() 创建属性列表
UpdateProcThreadAttribute 指定要继承的句柄
lpAttributeList STARTUPINFOEX 中的成员集
在调用 CreateProcess 时设置了 EXTENDED_STARTUPINFO_PRESENT 标志
需要Windows Vista,所以最初问这个问题时可能没有解决OPs问题,但现在每个人都在使用Vista或更高版本,对吧?:-)
如果您有权访问实际的文件句柄,则可以在调用 CreateProcess() 之前使用 SetHandleInformation() 删除 HANDLE_FLAG_INHERIT 标志。