Looking at the problem at the wrong level: Closing a process’s stdin


A customer was having trouble manipulating the stdin stream that was given to a process.

How do you simulate sending Ctrl+Z to a hidden console process programmatically?

I am using Redirect­Standard­Input and want to send the console a Ctrl+Z. I've tried sending ASCII code 26, but that doesn't work. Generate­Console­Ctrl­Event supports Ctrl+C and Ctrl+Break but not Ctrl+Z.

Here's what I'm doing, but it doesn't work:

ProcessStartInfo info = new ProcessStartInfo(@"...");
info.CreateNoWindow = true;
info.RedirectStandardError = true;
info.RedirectStandardOutput = true;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
Process p = Process.Start(info);
// 0x1A is ASCII code of Ctrl+Z but it does not work
p.StandardInput.WriteLine("\x1A");

The customer was kind enough to do more than simply ask the question. The customer set up the scenario and even provided a code fragment that illustrates the problem. Which is good, because the original question was the wrong question.

The customer asked about simulating typing Ctrl+Z to a console, but what they actually doing was sending a character to stdin; they weren't sending it to a console. In fact, the way they created the process, there is no console at all.

The customer confused stdin with consoles. It's true that Ctrl+Z is the convention used by console windows to indicate that stdin should be closed. But that is hardly any consolation when you took control of stdin yourself and are not using a console window to manage it.

It's like saying, "Normally, when I want somebody to take my order, I pull into a parking space and turn on my headlights, and somebody will come out. But I can't get it to work."

Um, that's because you pulled into your own driveway.

Ctrl+Z is a convention used by console windows to indicate that stdin should be closed, but if you said "I am going to manage stdin myself," then you aren't using a console window, and that convention carries no weight. If you write a Ctrl+Z to the process's stdin, it will simply read a Ctrl+Z. But since you are managing stdin yourself, you can do it yourself: Just take the stream you set as the process's stdin and close it.

Exercise: Perhaps you can answer this related question from a different customer:

I am trying to send a Ctrl+C (SIGINT) to a process.

CurrentProcess = new Process();
CurrentProcess.StartInfo.FileName = "foo.exe";
CurrentProcess.StartInfo.UseShellExecute = false;
CurrentProcess.StartInfo.RedirectStandardInput = true;
StandardInputWriter = CurrentProcess.StandardInput;
char c = '\u0003';
StandardInputWriter.Write(c);
StandardInputWriter.Flush();
StandardInputWriter.Close();

If I launch the process from a command prompt and type Ctrl+C, it flushes its output and terminates, but when I start it from within my application and send it a Ctrl+C via the code above, the process is still running. How do I send a Ctrl+C to a process?

Comments (11)
  1. GWO says:

    kill(pid,SIGINT);

  2. Adam Rosenfield says:

    Could you not use GenerateConsoleCtrlEvent? But in any case, assuming the you have the source code to foo.exe, you should rewrite it so that it exits after it hits EOF in its input stream.

  3. 640k says:

    Then why does Ctrl+C and Ctrl+Break work ("in your own driveway").

  4. Dan Bugglin says:

    @GWO Won't work on Windows.  Best you can do is a process kill, which may not cause the program to flush output, especially if it manages it's own output buffers that the OS doesn't know about

    @Adam Somehow I doubt that's the solution Raymond is looking for.

  5. Ian says:

    I think GenerateConsoleCtrlEvent() is the correct answer – although of course the sender has to be in the same console as the receiving process. If that isn't possible then you will have to work out some kind of IPC mechanism to signal to the receiving process that it should exit. I think Visual Studio does it by a proxy process that starts the console, starts the other process in the same console, and while that is running listens for a command (via some kind of IPC) that it should call GenerateConsoleCtrlEvent().

    Both problems share the similarity that whilst the customer is accustomed to sending Ctrl+C and Ctrl+Z via the keyboard, this isn't the same as writing Ctrl+C or Ctrl+Z to the console process's stdin. These inputs are dealt with at a different level – see the title.

  6. JS Bangs says:

    Calling GenerateConsoleCtrlEvent() won't work if the calling process is a GUI app or a service, because in that case there is no console.

    In any case, that's missing the point. As with the original post, once you've used the Process class, you have control, and it's up to you to do or simulate whatever the console would normally do on a Ctrl+C. Something like.

    proc.StandardInput.Flush();

    proc.StandardError.ReadToEnd();

    proc.StandardInput.ReadToEnd();

    proc.Kill();

  7. jtasler says:

    The Burger Master reference gave me a craving for one of their chocolate malts! ;-)

  8. You know, I always wondered how Burgermaster copes with all the cars that have daytime running lights (aka permanent-on headlights)…

  9. Drak says:

    @robinjm

    I assume those cars use their high beams to indicate they want to order something.

    (is high beams the right word here?)

  10. Erik says:

    @JS Bangs

    I believe your call to proc.StandardError.ReadToEnd() would block until the process itself closes the stderr. So would proc.StandardInput.ReadToEnd().

  11. Scott says:

    @robinjm

    At least in my car with daytime running lights, engaging the parking brake (even a small enough amount that the brake itself doesn't actually engage) is enough to turn off the daytime running lights.  Useful both at Burgermaster and on the ferry to avoid being yelled at.

Comments are closed.

Skip to main content