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 to stdout
based on the input. 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;
p.StandardInput.WriteLine(scriptcode);
p.Kill();
string error = p.StandardError.ReadToEnd();
if (!String.IsNullOrEmpty(error))
{
throw new Exception(error);
}
string output = p.StandardOutput.ReadToEnd();
The output is always empty, even though I get data back from stdout
when I run the exe manually.
Edit: This is C# 2.0 by the way.
Despite of the fact that using GenerateConsoleCtrlEvent for sending Ctrl+C signal is a right answer it needs significant clarification to get it work in different .NET application types.
If your .NET application doesn't use its own console (WinForms/WPF/Windows Service/ASP.NET) basic flow is:
The following code snippet illustrates how to do that:
Process p;
if (AttachConsole((uint)p.Id)) {
SetConsoleCtrlHandler(null, true);
try {
if (!GenerateConsoleCtrlEvent(CTRL_C_EVENT,0))
return false;
p.WaitForExit();
} finally {
FreeConsole();
SetConsoleCtrlHandler(null, false);
}
return true;
}
where SetConsoleCtrlHandler, FreeConsole, AttachConsole and GenerateConsoleCtrlEvent are native WinAPI methods:
internal const int CTRL_C_EVENT = 0;
[DllImport("kernel32.dll")]
internal static extern bool GenerateConsoleCtrlEvent(uint dwCtrlEvent, uint dwProcessGroupId);
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool AttachConsole(uint dwProcessId);
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)]
internal static extern bool FreeConsole();
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
// Delegate type to be used as the Handler Routine for SCCH
delegate Boolean ConsoleCtrlDelegate(uint CtrlType);
Things become more complex if you need to send Ctrl+C from .NET console application. Approach will not work because AttachConsole returns false in this case (main console app already has a console). It is possible to call FreeConsole before AttachConsole call but as result original .NET app console will be lost which is not acceptable in most cases.
My solution for this case (that really works and has no side effects for .NET main process console):