C++ 使用新控制台窗口创建进程,但覆盖某些std i/o句柄
如果将CreateProcess与标志CREATE_NEW_CONSOLE一起使用,则新进程将其标准输入、输出和错误句柄定向到新控制台窗口。如果要覆盖I/O流,可以通过在STARTUPINFO字段hStdOutput、hStdInput和hStdError中设置句柄并设置STARTF_USESTDHANDLES标志来实现 但是如果您只想覆盖其中一个句柄,该怎么办?例如,我可能希望将stderr重定向到一个文件,同时将stdout和stdin连接到新的控制台窗口 STARTF_USESTDHANDLES标志告诉CreateProcess替换所有句柄,而不是将它们连接到新控制台窗口的句柄。因此,似乎我们必须提供所有三个手柄。显然,我可以将hStdError设置为日志文件的句柄,但是hStdInput和hStdOutput应该使用什么值呢 我尝试使用NULL,它似乎在Windows8.1上工作,但在Windows7上不工作C++ 使用新控制台窗口创建进程,但覆盖某些std i/o句柄,c++,winapi,console,stdio,createprocess,C++,Winapi,Console,Stdio,Createprocess,如果将CreateProcess与标志CREATE_NEW_CONSOLE一起使用,则新进程将其标准输入、输出和错误句柄定向到新控制台窗口。如果要覆盖I/O流,可以通过在STARTUPINFO字段hStdOutput、hStdInput和hStdError中设置句柄并设置STARTF_USESTDHANDLES标志来实现 但是如果您只想覆盖其中一个句柄,该怎么办?例如,我可能希望将stderr重定向到一个文件,同时将stdout和stdin连接到新的控制台窗口 STARTF_USESTDHAND
我还考虑先创建一个控制台窗口,然后用句柄调用CreateProcess到新控制台窗口的缓冲区(并省略CREATE_new_console标志)。不幸的是,父进程也是一个控制台应用程序,控制台应用程序似乎无法创建第二个控制台窗口。如果我解释正确,您应该使用
GetStdHandle(STD\u INPUT\u HANDLE)
和GetStdHandle(STD\u OUTPUT\u HANDLE)
用于其他两个句柄。根据本MSDN支持文章:
如果父进程只希望重定向一个或两个标准句柄,则为特定句柄指定GetStdHandle(),会导致子进程按照正常方式创建标准句柄,而无需重定向。例如,如果父进程只需要重定向子进程的标准输出和错误,然后,STARTUPINFO结构的hStdInput成员填充如下:
hStdInput = GetStdHandle(STD_INPUT_HANDLE);
根据报告:
标准输入句柄(德沃德)-10
标准输入设备最初,这是控制台输入缓冲区,CONIN$ 标准输出句柄
(德沃德)-11
标准输出设备最初,这是活动的控制台屏幕缓冲区,CONOUT$ 标准错误句柄
(德沃德)-12
标准误差装置最初,这是活动的控制台屏幕缓冲区,CONOUT$ 进程的标准句柄可以通过调用SetStdHandle重定向,在这种情况下,GetStdHandle返回重定向的句柄。如果已重定向标准句柄,则可以在调用CreateFile函数以获取控制台输入缓冲区的句柄时指定CONIN$值。类似地,您可以指定CONOUT$值来获取控制台活动屏幕缓冲区的句柄 附加/分离行为 当连接到新控制台时,除非在进程创建过程中指定了STARTF_USESTDHANDLES,否则标准句柄始终替换为控制台句柄。 如果标准句柄的现有值为NULL,或者标准句柄的现有值看起来像控制台伪句柄,则该句柄将替换为控制台句柄。 当父级同时使用CREATE\u NEW\u CONSOLE和STARTF\u USESTDHANDLES创建控制台进程时,除非标准句柄的现有值为NULL或控制台伪句柄,否则不会替换标准句柄。 因此,如果父进程的STDIN没有被重定向,
GetStdHandle(STD\u INPUT\u HANDLE)
将返回NULL或引用CONIN$
的伪句柄。当通过STARTUPINFO
将该值传递给子进程时,子进程将收到一个STDIN的控制台句柄,该句柄位于运行它的任何控制台中。另一方面,如果父进程的STDIN已被重定向,GetStdHandle(STD\u INPUT\u HANDLE)
将返回一个实际句柄到子进程将继承和访问的实际文件/管道/etc
这同样适用于STDOUT和STDERR
因此,如果要重定向孩子的STDIN/OUT/ERR句柄,必须将
hStdInput/Output/Error
设置为自己的句柄。如果您想让孩子接收默认句柄,请使用GetStdHandle()
,并让CreateProcess()
根据父进程本身是否被重定向来决定孩子接收的句柄类型。至少在Windows 7上,(如现有答案所引用的)是误导性的。建议的方法仅在父进程没有重定向输入时有效
这是在我的机器上观察到的实际行为:
- 当进程打开CONOUT$的句柄时(例如),返回的句柄总是具有相同的数值(在我的机器上,CONOUT$的句柄总是7),除非该句柄已经存在
- 因此,如果您是一个控制台进程,并且启动时没有重定向输出,那么您的标准输出句柄是7。如果打开CONOUT$的另一个句柄,它将具有不同的值。如果关闭句柄7,然后打开CONOUT$的句柄,您将再次得到7
- 当启动控制台进程时,子进程中通常会出现一个CONOUT$的句柄,该句柄的神奇值为7(不考虑重定向)。如果您使用了
,则当且仅当您指定7作为标准输出句柄时,子级的标准输出才会转到控制台。如果您为CONOUT$指定一个具有任何其他值的句柄,则该句柄将不起作用STARTF\u USESTDHANDLES
- 有时,在标准输出重定向的情况下启动控制台进程时,子进程中没有CONOUT$的句柄。特别是,当
启动ccmd.exe