CreateProcess与新的控制台窗口,但重写一些std i / o句柄 [英] CreateProcess with new console window, but override some std i/o handles

查看:754
本文介绍了CreateProcess与新的控制台窗口,但重写一些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,这似乎在Windows上工作8.1,但它在Windows 7上不起作用。



我还考虑过先创建一个控制台窗口,然后调用CreateProcess与新的控制台窗口的缓冲区并省略CREATE_NEW_CONSOLE标志)。不幸的是,父进程也是一个控制台应用程序,似乎控制台应用程序不能创建第二个控制台窗口。

解决方案

至此MSDN支持文章:



如何生成带有重定向标准句柄的控制台进程


如果父进程只想重定向一个或两个标准例如,如果父进程只需要重定向子进程的标准输出和错误,那么,那么STARTUPINFO结构的hStdInput成员被填充如下:

  hStdInput = GetStdHandle(STD_INPUT_HANDLE); 


根据 GetStdHandle()文档


STD_INPUT_HANDLE

(DWORD)-10

标准输入设备。 最初,这是控制台输入缓冲区CONIN $



STD_OUTPUT_HANDLE

(DWORD)
标准输出设备。 最初,这是活动的控制台屏幕缓冲区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)将返回一个实际的句柄到一个真正的文件/管道/ etc,它将继承和访问。 / p>

这同样适用于STDOUT和STDERR。



所以,如果你想重定向孩子的STDIN / ERR句柄,你必须设置 hStdInput / Output / Error 到你自己的句柄。如果你想要孩子接收默认处理,使用 GetStdHandle()并让 CreateProcess()决定什么样的句柄该子项根据父项本身是否被重定向来接收。


If you use CreateProcess with the flag CREATE_NEW_CONSOLE, the new process has its standard input, output, and error handles directed to the new console window. If you want to override the I/O streams, you can do so by setting the handles in STARTUPINFO fields hStdOutput, hStdInput, and hStdError and setting the flag STARTF_USESTDHANDLES.

But what if you want to override only one of the handles? For example, I might want to redirect stderr to a file while leaving the stdout and stdin connected to the new console window.

The STARTF_USESTDHANDLES flag tells CreateProcess to replace all of the handles instead of connecting them to the ones for the new console window. So it seems we must provide all three handles. Obviously I can set hStdError to the handle of the log file, but what values should be used for hStdInput and hStdOutput?

I tried using NULL, which seems to work on Windows 8.1, but it doesn't work on Windows 7.

I also thought about creating a console window first, and then calling CreateProcess with handles to the new console window's buffers (and omitting the CREATE_NEW_CONSOLE flag). Unfortunately, the parent process is also a console application, and it seems a console application cannot create a second console window.

解决方案

According to this MSDN Support article:

How to spawn console processes with redirected standard handles

If the parent process only wishes to redirect one or two standard handles, specifying GetStdHandle() for the specific handles causes the child to create the standard handle as it normally would without redirection. For example, if the parent process only needs to redirect the standard output and error of the child process, then the hStdInput member of the STARTUPINFO structure is filled as follows:

hStdInput = GetStdHandle(STD_INPUT_HANDLE);

According to the GetStdHandle() documentation:

STD_INPUT_HANDLE
(DWORD)-10
The standard input device. Initially, this is the console input buffer, CONIN$.

STD_OUTPUT_HANDLE
(DWORD)-11
The standard output device. Initially, this is the active console screen buffer, CONOUT$.

STD_ERROR_HANDLE
(DWORD)-12
The standard error device. Initially, this is the active console screen buffer, CONOUT$.

...

The standard handles of a process may be redirected by a call to SetStdHandle, in which case GetStdHandle returns the redirected handle. If the standard handles have been redirected, you can specify the CONIN$ value in a call to the CreateFile function to get a handle to a console's input buffer. Similarly, you can specify the CONOUT$ value to get a handle to a console's active screen buffer.

Attach/detach behavior

When attaching to a new console, standard handles are always replaced with console handles unless STARTF_USESTDHANDLES was specified during process creation.

If the existing value of the standard handle is NULL, or the existing value of the standard handle looks like a console pseudohandle, the handle is replaced with a console handle.

When a parent uses both CREATE_NEW_CONSOLE and STARTF_USESTDHANDLES to create a console process, standard handles will not be replaced unless the existing value of the standard handle is NULL or a console pseudohandle.

So, if the parent process's STDIN has NOT been redirected, GetStdHandle(STD_INPUT_HANDLE) will return either NULL or a pseudo-handle that refers to CONIN$. When that value is passed to the child process via STARTUPINFO, the child process will receive a console handle for the STDIN of whichever console it happens to be running in. On the other hand, if the parent process's STDIN has been redirected, GetStdHandle(STD_INPUT_HANDLE) will return an actual handle to a real file/pipe/etc, which the child will inherit and access.

The same applies to STDOUT and STDERR.

So, if you want to redirect the child's STDIN/OUT/ERR handles, you have to set hStdInput/Output/Error to your own handles. If you want the child to receive default handles, use GetStdHandle() and let CreateProcess() decide what kind of handles the child receives based on whether the parent is itself being redirected or not.

这篇关于CreateProcess与新的控制台窗口,但重写一些std i / o句柄的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆