如果将CreateProcess与标志CREATE_NEW_CONSOLE一起使用,则新进程将其标准输入,输出和错误句柄定向到新控制台窗口。如果要覆盖I / O流,可以通过设置STARTUPINFO字段hStdOutput,hStdInput和hStdError中的句柄并设置标志STARTF_USESTDHANDLES来实现。
但是如果你只想覆盖其中一个句柄呢?例如,我可能希望将stderr重定向到文件,同时将stdout和stdin连接到新的控制台窗口。
STARTF_USESTDHANDLES标志告诉CreateProcess替换所有句柄,而不是将它们连接到新控制台窗口的句柄。所以看来我们必须提供所有三个句柄。显然我可以将hStdError设置为日志文件的句柄,但是hStdInput和hStdOutput应该使用什么值?
我尝试使用NULL,这似乎适用于Windows 8.1,但它在Windows 7上不起作用。
我还考虑先创建一个控制台窗口,然后使用句柄调用CreateProcess到新控制台窗口的缓冲区(并省略CREATE_NEW_CONSOLE标志)。不幸的是,父进程也是一个控制台应用程序,似乎控制台应用程序无法创建第二个控制台窗口。
答案 0 :(得分:4)
根据此MSDN支持文章:
How to spawn console processes with redirected standard handles
如果父进程只希望重定向一个或两个标准句柄,则为特定句柄指定GetStdHandle()会导致子进程创建标准句柄,而不需要重定向。例如,如果父进程只需要重定向子进程的标准输出和错误,那么STARTUPINFO结构的hStdInput成员将按如下方式填充:
hStdInput = GetStdHandle(STD_INPUT_HANDLE);
根据GetStdHandle()
documentation:
STD_INPUT_HANDLE
(DWORD)-10
标准输入设备。 最初,这是控制台输入缓冲区,CONIN $ 。STD_OUTPUT_HANDLE
(DWORD)-11
标准输出设备。 最初,这是主动控制台屏幕缓冲区,CONOUT $ 。STD_ERROR_HANDLE
(DWORD)-12
标准错误设备。 最初,这是主动控制台屏幕缓冲区,CONOUT $ 。...
可以通过调用SetStdHandle来重定向进程的标准句柄,在这种情况下,GetStdHandle返回重定向的句柄。如果已重定向标准句柄,则可以在调用CreateFile函数时指定CONIN $值以获取控制台输入缓冲区的句柄。同样,您可以指定CONOUT $值以获取控制台的活动屏幕缓冲区的句柄。
附加/分离行为
连接到新控制台时,除非在创建流程期间指定了STARTF_USESTDHANDLES,否则标准句柄始终替换为控制台句柄。
如果标准句柄的现有值为NULL,或者标准句柄的现有值看起来像控制台伪句柄,则句柄将替换为控制台句柄。
当父级使用CREATE_NEW_CONSOLE和STARTF_USESTDHANDLES创建控制台进程时,除非标准句柄的现有值为NULL或控制台伪句柄,否则不会替换标准句柄。
因此,如果未重定向父进程的STDIN,GetStdHandle(STD_INPUT_HANDLE)
将返回NULL或引用CONIN$
的伪句柄。当该值通过STARTUPINFO
传递给子进程时,子进程将收到它正好运行的控制台的STDIN控制台句柄。另一方面,如果父进程的STDIN已被重定向,GetStdHandle(STD_INPUT_HANDLE)
将返回真实文件/管道/等的实际句柄,孩子将继承并访问。
这同样适用于STDOUT和STDERR。
因此,如果要重定向子项的STDIN / OUT / ERR句柄,则必须将hStdInput/Output/Error
设置为自己的句柄。如果您希望孩子接收默认句柄,请使用GetStdHandle()
并让CreateProcess()
根据父母本身是否被重定向来决定孩子接收的句柄类型。
答案 1 :(得分:2)
至少在Windows 7上,documentation here(由现有答案引用)具有误导性。建议的方法仅在父进程没有重定向输入时才有效。
这是我的机器上观察到的实际行为:
当进程打开CONOUT $的句柄时(例如),返回的句柄总是具有相同的数值(在我的机器上,CONOUT $的句柄总是7),除非该句柄已存在。
因此,如果您是一个控制台进程,并且未使用重定向输出启动,则标准输出句柄为7.如果打开另一个CONOUT $句柄,它将具有不同的值。如果您关闭手柄7,然后打开CONOUT $的手柄,您将再次获得7。
启动控制台进程时,子进程中通常会出现一个带有魔术值7的CONOUT $句柄(无论重定向如何)。如果您已使用STARTF_USESTDHANDLES
,则当且仅当您将7指定为标准输出句柄时,子项的标准输出才会转到控制台。如果指定CONOUT $的句柄具有任何其他值,则它将不起作用。
有时,当启动控制台进程并重定向标准输出时,子进程中不存在CONOUT $句柄。特别是,当cmd.exe
启动带有重定向标准输出的控制台进程时,会发生这种情况。到目前为止,我一直无法弄清楚要与CreateProcess一起使用哪些参数组合来实现这一目标。
CONIN $的行为类似;在我的机器上,CONIN $的神奇值是3.(我没有调查标准错误是如何工作的。)
结果是我不相信使用这种行为是安全的,除非您完全控制父进程的启动方式,因为除非标准句柄已指向控制台,否则没有可靠的方法使用正确的魔术值获取控制台的句柄。
相反,使用CREATE_NEW_CONSOLE
和启动代理流程,而不使用 STARTF_USESTDHANDLES
。从那个进程开始,既然您知道它是如何启动的,那么您就知道标准句柄将具有正确的魔术值,因此将它们指定为子进程的句柄是安全的。
答案 2 :(得分:1)
如果我正确解释this documentation,您应该使用GetStdHandle(STD_INPUT_HANDLE)
和GetStdHandle(STD_OUTPUT_HANDLE)
作为其他两个句柄。