808140
808140

Reputation: 205

Redirection of console output to a buffer by a non-console process

Here's the situation: we have a build server, which services requests over a socket and exposes no UI to the machine it is running on. Based on the requests it receives, it launches build scripts (which are typically MS batch files) and serves the files these produce. For diagnostic purposes, the build scripts are launched with stdout and stderr redirected to a pipe, and this output is saved into a buffer by the build server application and passed back to the client requesting the build. (That way, if the build fails, the person who requested the build can see what the error message was.)

During debug, this build server was built as a console application, mainly for the convenience of being able to print diagnostic messages (client connected, request made, etc). Once everything was working just right, I rebuilt it as a non-console app.

Suddenly, the behavior of the application changed. The output captured by the pipe was reduced to only the output directly generated by the batch file (i.e. commands echoed, in this case, since echo wasn't off). The subprocesses launched by the batch files (such as MSBuild, nmake, and others) opened up console windows and directed their output to the windows instead of to the pipe.

I suspect what's happening is that when the application was a console app, the console application didn't attempt to manage its own input/output and instead inherited from the running console, resulting in the _dup2 on the I/O fds staying live. Thus everything worked fine. But in the situation where the parent build server didn't create a console window, the subprocesses spawned by the batch file felt the need to create their own and handle their own I/O, robbing the build server of the captured output (not to mention being extremely annoying to anyone connected to the server's desktop).

So basically the question is simple: how can a non-console launch applications and prevent this behavior? I know it's possible in principle for most console apps because Emacs shell-mode is an example of a non-console application capturing and redirecting command output on Windows, but I have no idea how to do it.

Currently I am using Win32's POSIX-flavored CRT functions: _pipe, _dup, _dup2, _close, _spawnvp, and _read. I'm aware that these are thin wrappers around the "real" win32 functions but being a UNIX guy by training I figured I'd save myself the trouble of wading through CreateProcess and friends.

Development language needs to be C, because the build server is actually written in Haskell and linking C is simpler. (For any of you Haskellers out there -- I rolled my own spawn/redirect code and linked with the FFI instead of using System.Process because I crucially need both stdout and stderr redirected, and on Windows this is non-trivial to do in pure Haskell).

Of course I can use the build server as a console app and just minimize it on the server, no big deal, it works great if I do that. But I'd rather not ... any ideas?

EDIT: Thought I might mention that I don't do anything with stdin. Should I be creating a stdin fd, maybe? These scripts aren't interactive.

Upvotes: 1

Views: 1159

Answers (2)

Jim Mischel
Jim Mischel

Reputation: 133975

You could call AllocConsole to create a console, but that's not fundamentally different from creating the application as a console app.

I think a better solution would be to open your log file and then call SetStdHandle, passing it STD_OUTPUT_HANDLE and the handle of the file that you just opened. I think that should give you a stdout that the other processes will write to.

Alternatively, you could perhaps find a way to hide that console window completely (remove it from the task bar, etc.)

Additional info:

You could perhaps try getting the console window handle and calling ShowWindow(handle, SW_HIDE). That removes the window from the screen, and yet when you write to stdout it actually writes to that window. You should be able to get the console window handle by calling GetConsoleWindow.

If that doesn't work, you could have your program take a parameter -hide. If that is on the command line, then the program starts a new copy of itself, but in the process start info it says to start the process with a hidden window.

Upvotes: 1

Carey Gregory
Carey Gregory

Reputation: 6846

This problem has been addressed several times on SO. Take a look at this question, for example.

Upvotes: 0

Related Questions