Take the 2-minute tour ×

I'm writing a wrapper class for a command line executable. This exe accepts input from stdin until i hit ctrl+c in the command prompt shell, in which case it prints output based on the input to stdout. I want to simulate that ctrl+c press in c# code, sending the kill command to a .Net process object. I've tried calling Process.kill(), but that doesn't seem to give me anything in the process's StandardOutput StreamReader. Might there be anything I'm not doing right? Here's the code I'm trying to use:

ProcessStartInfo info = new ProcessStartInfo(exe, args);
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
Process p = Process.Start(info);

p.StandardInput.AutoFlush = true;


string error = p.StandardError.ReadToEnd();
if (!String.IsNullOrEmpty(error)) 
     throw new Exception(error);
string output = p.StandardOutput.ReadToEnd();

however output is always empty even though I get data back from stdout when I run the exe manually. edit: this is c# 2.0 btw

share|improve this question

4 Answers 4

up vote 14 down vote accepted

I've actually just figured out the answer. Thank you both for your answers, but it turns out that all i had to do was this:


which causes the program I've spawned to finish reading from stdin and output what i need.

share|improve this answer
Note that it only works if the process is trying to read from standard input. Closing the stdin does nothing until the program tries to read something from it. –  Doug Mar 12 '13 at 23:00

@alonl: The user is attempting to wrap a command-line program. Command-line programs don't have message pumps unless they are specifically created, and even if that was the case, Ctrl+C doesn't have the same semantics in a Windows-environment application (copy, by default) as it does in a command-line environment (Break).

I threw this together. CtrlCClient.exe simply calls Console.ReadLine() and waits:

        static void Main(string[] args)
            ProcessStartInfo psi = new ProcessStartInfo("CtrlCClient.exe");
            psi.RedirectStandardInput = true;
            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError = true;
            psi.UseShellExecute = false;
            Process proc = Process.Start(psi);
            Console.WriteLine("{0} is active: {1}", proc.Id, !proc.HasExited);
My output seems to do what you want:
4080 is active: True

4080 is active: False

Hope that helps!

(To clarify: \x3 is the hex escape sequence for the hex character 3, which is ctrl+c. It's not just a magic number. ;) )

share|improve this answer
Using a test program that both assigns Console.CancelKeyPress delegate and do a Console.ReadLine(); the proposed solution of StandardInput.WriteLine("\x3"); does complete the ReadLine call but does not (for me) trigger the CancelKeyPress delegate. Bug / incorrect correctness demonstration because any input, not just ctrl+c, triggers a process exit? (Hitting ctrl+c on the keyboard does trigger the delegate for me) –  David Burg Jan 15 '13 at 2:40
@David Burg: Possibly a bugfix in framework code? The post was authored three versions and > 4 years ago. –  Rob Jan 15 '13 at 6:17

Ok, here is a solution.

The way to send the Ctrl-C signal is with GenerateConsoleCtrlEvent. HOWEVER, this call takes a processGroupdID parameter, and sends the Ctrl-C signal to all processes in the group. This would be fine if it weren't for the fact that there is no way spawn child process in .net that is in a different process group than you (the parent) are in. So, when you send the GenerateConsoleCtrlEvent, both the child AND YOU (THE PARENT) GET IT. So, you need to capture the ctrl-c event in the parent too, and then determine if you ned to ignore it not.

In my case, I want the parent to be able to handle Ctrl-C events also, so I need to distnguish between Ctrl-C events sent by the user on the console, and those sent by the parent process to the child. I do this by just hackishly setting/unsetting a boolean flag while send the ctrl-c to the child, and then checking for this flag in the parent's ctrl-c event handler (ie. if send ctrl-c to child, then ignore.)

So, the code would look something like this:

//import in the declaration for GenerateConsoleCtrlEvent
static extern bool GenerateConsoleCtrlEvent(ConsoleCtrlEvent sigevent, int dwProcessGroupId);
public enum ConsoleCtrlEvent  
    CTRL_C = 0,  
    CTRL_BREAK = 1,  
    CTRL_CLOSE = 2,  
    CTRL_LOGOFF = 5,  

//set up the parents CtrlC event handler, so we can ignore the event while sending to the child
public static volatile bool SENDING_CTRL_C_TO_CHILD = false;
static void Console_CancelKeyPress(object sender, ConsoleCancelEventArgs e)

//the main method..
static int Main(string[] args)
    //hook up the event handler in the parent
    Console.CancelKeyPress += new ConsoleCancelEventHandler(Console_CancelKeyPress);

    //spawn some child process
    System.Diagnostics.ProcessStartInfo psi = new System.Diagnostics.ProcessStartInfo();
    psi.Arguments = "childProcess.exe";
    Process p = new Process();
    p.StartInfo = psi;

    //sned the ctrl-c to the process group (the parent will get it too!)
    GenerateConsoleCtrlEvent(ConsoleCtrlEvent.CTRL_C, p.SessionId);        

    //note that the ctrl-c event will get called on the parent on background thread
    //so you need to be sure the parent has handled and checked SENDING_CTRL_C_TO_CHILD
    already before setting it to false. 1000 ways to do this, obviously.

    //get out....
    return 0;
share|improve this answer
Couple improvements to the import per StyleCop and FxCop rules. Too long for comment so will attempt inline... –  David Burg Jan 14 '13 at 19:43
p.SessionId is not a correct parameter to GenerateConsoleCtrlEvent. –  Kevin Smyth Oct 3 '13 at 17:11

Try actually sending the Key Combination Ctrl+C, instead of directly terminating the process:

        public static extern int SendMessage(
              int hWnd,      // handle to destination window
              uint Msg,       // message
              long wParam,  // first message parameter
              long lParam   // second message parameter

Look it up on the MSDN, you should find what you need there in order to send the Ctrl+Key combination... I know that the message you need for sending Alt+Key is WM_SYSTEMKEYDOWN and WM_SYSTEMKEYUP, can't tell you about Ctrl...

share|improve this answer

Your Answer


