0

Is it possible to detach a running process from its console and hand ownership of that console back to the parent process?

That is, I would like a process started from cmd.exe to detach itself from the console (i.e. closing the console doesn't kill the process) and keep running in the background, while control of the standard input, output and error streams are handed back to cmd.exe so that the user can continue running commands.

In essence, I'm trying to roughly approximate the appearance of calling fork on Linux.

I'm currently doing:

#include <windows.h>

int main() {
    FreeConsole();
    Sleep(10000);
    return 0;
}

This keeps the process alive even if the console window is closed, but control of the standard streams is not handed back to cmd.exe until the sleep times out and the process terminates.

EDIT: the functionality is part of a cross-platform library and may be called from an arbitrary point in the user's code, so refactoring the application into something more Windows-y, calling external commands, restarting the process (or starting the process from another parent process in a two-step launch sequence), creating a Windows service, etc. are unfortunately not viable solutions.

valderman
  • 8,365
  • 4
  • 22
  • 29
  • Try running your process with `START /B program` – learning_frog Aug 09 '16 at 13:52
  • Pass CREATE_NEW_CONSOLE to CreateProcess – David Heffernan Aug 09 '16 at 13:53
  • The `fork`-ish function I'm trying to implement is part of a library and can appear just about anywhere in client code. Thus, restarting the process, wither with an external command or `CreateProcess` isn't feasible. – valderman Aug 09 '16 at 13:57
  • 2
    You likely need to be a little more flexible. Implementing fork on Windows isn't viable. – David Heffernan Aug 09 '16 at 14:09
  • Indeed it is not viable, which is why I'm trying to figure out if it is possible to approximate this one particular aspect of it. If this turns out to be impossible, then that is also a valid answer to the question. – valderman Aug 09 '16 at 14:14
  • If you really want `fork()` on windows, see how [cygwin does it](https://www.cygwin.com/faq.html#faq.api.fork). Or just use cygwin. – PC Luddite Aug 09 '16 at 14:35
  • Now that the question has been updated, it is really no different than previous questions that ask for a `fork`-equivalent on Windows, so I've marked this one as a duplicate of one that has some pretty good answers. Anyway, if you're trying to emulate Unix semantics that closely and can't redesign the architecture, my recommendation would be to actually use the POSIX-compatible subsystem built into Windows. The latest build of Win 10 actually has a complete Ubuntu-based Bash shell built in, and downlevel (earlier) versions of Windows have the Subsystem for UNIX Applications. – Cody Gray - on strike Aug 09 '16 at 22:07
  • The phrase "control of the standard streams is not handed back to cmd.exe" makes no sense on Windows. Neither does "console ownership". I *think* what you mean is that `cmd.exe` is waiting for your process to exit, and you don't want it to. This has nothing to do with the standard streams or the console. The usual solution is for your program to launch a second copy of itself (perhaps with CREATE_NO_WINDOW) and then exit. – Harry Johnston Aug 09 '16 at 22:45
  • @HarryJohnston I see. I didn't even consider that, which was pretty stupid of me. If you post this as an answer, I'll accept it. – valderman Aug 10 '16 at 11:41

2 Answers2

2

Windows does not have a notion of fork; its process model is very different from Linux, and as such, you should design your application architecture differently for the two operating systems. There isn't enough information given in the question for me to be able to suggest alternative designs, however.

In the specific case that you described, you might be able to get away with calling FreeConsole to detach the console window from the process. Now, the problem with this is that the console is automatically destroyed if it is not shared with any other processes. So you will need to call AttachConsole from another process first so that the console is shared between the two processes, then detach the console (by calling FreeConsole) from the original process. I have no idea if that would actually work; I've never attempted something like it. It also doesn't solve the problem of transferring ownership of streams.

If you want an application that sometimes displays output in a console window but is not tied to that console window (and can keep running in the background), consider creating a standard Windows application instead of a console application, and then allocating and freeing the console as needed.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • Indeed, that is why I'm just trying to approximate the "detaching from console" aspect of it and not reimplement its actual semantics, which would be quite hairy if the Cygwin implementation is anything to go by. If this were a standalone application I would definitely redesign, but that's unfortunately not an option here (see edit for more context). – valderman Aug 09 '16 at 14:02
1

Your question is based on a misunderstanding. Windows does not have the concept of stream ownership or of console ownership. (When multiple processes are running on the same console, console input may be fed to any process that asks for it; under most circumstances, only one process will have a read pending on the console at a time.)

What you're observing is that, by default, cmd.exe waits for console applications to exit. (When running a batch file, it also waits for GUI applications to exit.) There is no way for the application to change this behavior.

The usual solution is for the executable to launch another copy of itself as a child process (typically with the CREATE_NO_WINDOW option) and then exit, which works because cmd.exe only waits for the process it launched to exit rather than the entire process tree. Unfortunately, this approach is typically only useful if it is the first thing the program does (because you can't sensibly implement fork in Windows) and it sounds as if that's not your situation.

If you must implement this feature, you could perhaps provide the programmer with a function to call at process startup that on Windows relaunches the executable and then never returns. In this scenario, you wouldn't use the CREATE_NO_WINDOW option (since the child may want to talk to the console up until the point where it backgrounds itself) and after calling FreeConsole() you'd use IPC to make the parent process exit. (It will also have to exit if the child does. And you might want to reverse that logic too and have the child die if the parent process is killed, if this happens before the program backgrounds itself.)

Personally, I'm of the opinion that cross-platform libraries should typically only attempt to implement functionality that actually makes sense on all the relevant platforms. Native Windows applications never work this way, so it arguably doesn't make sense to worry about making cross-platform applications do so when running on Windows. YMMV.

Community
  • 1
  • 1
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
  • 1
    Great answer, great suggestions for a workaround! I ended up splitting the POSIXy parts of the library into a separate module hierarchy which only gets built on non-Windows systems, in the spirit of the last paragraph of this answer. – valderman Aug 12 '16 at 13:06