Adr*_*thy 6 c++ console winapi createprocess stdio
如果您使用带有 CREATE_NEW_CONSOLE 标志的 CreateProcess,则新进程会将其标准输入、输出和错误句柄定向到新控制台窗口。如果要覆盖 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 支持文章:
如果父进程只希望重定向一个或两个标准句柄,则为特定句柄指定 GetStdHandle() 会导致子进程像通常没有重定向一样创建标准句柄。比如父进程只需要重定向子进程的标准输出和错误,那么STARTUPINFO结构体的hStdInput成员填充如下:
Run Code Online (Sandbox Code Playgroud)hStdInput = GetStdHandle(STD_INPUT_HANDLE);
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()根据父级本身是否被重定向来决定子级接收哪种类型的句柄。