通过非控制台进程将控制台输出重定向到缓冲区

时间:2011-09-16 13:06:34

标签: c winapi

情况就是这样:我们有一个构建服务器,它通过套接字为请求提供服务,并且不向它运行的机器公开UI。根据它收到的请求,它启动构建脚本(通常是MS批处理文件)并提供这些产生的文件。出于诊断目的,使用stdout和stderr将构建脚本重定向到管道,并且此输出由构建服务器应用程序保存到缓冲区中,并传递回请求构建的客户端。 (这样,如果构建失败,请求构建的人可以看到错误消息是什么。)

在调试期间,此构建服务器构建为控制台应用程序,主要是为了便于打印诊断消息(客户端连接,请求等)。一切正常后,我将其重建为非控制台应用程序。

突然,应用程序的行为发生了变化。由管道捕获的输出仅减少到由批处理文件直接生成的输出(即,在这种情况下回显的命令,因为回声没有关闭)。批处理文件(例如MSBuild,nmake等)启动的子进程打开了控制台窗口,并将其输出定向到窗口而不是管道。

我怀疑发生了什么,当应用程序是一个控制台应用程序时,控制台应用程序没有尝试管理自己的输入/输出,而是从正在运行的控制台继承,导致我_dup2 / O fds住在一起。一切顺利。但是在父构建服务器没有创建控制台窗口的情况下,批处理文件生成的子进程感觉需要创建自己的并处理自己的I / O,抢夺捕获的输出的构建服务器(而不是提到连接到服务器桌面的任何人都非常讨厌。)

所以基本上问题很简单:非控制台如何启动应用程序并防止这种行为?我知道大多数控制台应用程序原则上是可行的,因为Emacs shell模式是在Windows上捕获和重定向命令输出的非控制台应用程序的示例,但我不知道该怎么做。

目前我正在使用Win32的POSIX风格的CRT功能:_pipe_dup_dup2_close_spawnvp_read 。我知道这些是围绕“真正的”win32功能的薄包裹,但是通过训练成为一个UNIX人我认为我可以省去趟过CreateProcess和朋友的麻烦。

开发语言需要是C,因为构建服务器实际上是用Haskell编写的,而链接C更简单。 (对于你们中的任何一个Haskellers - 我滚动了我自己的spawn / redirect代码并与FFI链接而不是使用System.Process,因为我至关重要地需要重定向stdoutstderr,并且在Windows上这在纯粹的Haskell中是非常重要的。)

当然,我可以将构建服务器用作控制台应用程序,只需将其最小化在服务器上,没什么大不了的,如果我这样做的话,效果很好。但我宁愿不......任何想法?

编辑:我想我可能会提到我对stdin没有做任何事情。我可以创建一个stdin fd吗?这些脚本不是交互式的。

2 个答案:

答案 0 :(得分:1)

您可以调用AllocConsole来创建控制台,但这与将应用程序创建为控制台应用程序没有根本区别。

我认为更好的解决方案是打开日志文件,然后调用SetStdHandle,传递STD_OUTPUT_HANDLE和刚刚打开的文件句柄。我认为这应该给你一个其他进程将写入的标准。

或者,你也许可以找到一种完全隐藏控制台窗口的方法(从任务栏中删除它等)。

其他信息:

您也许可以尝试获取控制台窗口句柄并调用ShowWindow(handle, SW_HIDE)。这会从屏幕中删除窗口,但是当你写入stdout时,它实际上会写入该窗口。您应该可以通过调用GetConsoleWindow来获取控制台窗口句柄。

如果这不起作用,您可以让程序采用参数-hide。如果这是在命令行上,那么程序会启动一个新的自身副本,但在进程启动信息中它表示使用隐藏窗口启动进程。

答案 1 :(得分:0)

此问题已在SO上多次解决。例如,请查看this question

相关问题