Last active
February 18, 2024 02:23
-
-
Save jvshahid/6fb2f91fa7fb1db23599 to your computer and use it in GitHub Desktop.
C# terminating a child process (as opposed to killing, i.e. sigkill vs. sigint on linux)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Runtime.InteropServices; | |
using System.Text; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace TestCtrlEvent | |
{ | |
class Program | |
{ | |
[DllImport("kernel32.dll", SetLastError = true)] | |
static extern bool AttachConsole(uint dwProcessId); | |
[DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] | |
static extern bool FreeConsole(); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); | |
[DllImport("Kernel32", SetLastError = true)] | |
private static extern bool SetConsoleCtrlHandler(HandlerRoutine handler, bool add); | |
// Enumerated type for the control messages sent to the handler routine | |
enum CtrlTypes | |
{ | |
CTRL_C_EVENT = 0, | |
CTRL_BREAK_EVENT, | |
CTRL_CLOSE_EVENT, | |
CTRL_LOGOFF_EVENT = 5, | |
CTRL_SHUTDOWN_EVENT | |
} | |
// A delegate type to be used as the handler routine | |
// for SetConsoleCtrlHandler. | |
private delegate bool HandlerRoutine(CtrlTypes CtrlType); | |
public static void StopProgram(Process proc) | |
{ | |
//This does not require the console window to be visible. | |
//Disable Ctrl-C handling for our program | |
// SetConsoleCtrlHandler(null, true); | |
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0); | |
//Must wait here. If we don't and re-enable Ctrl-C | |
//handling below too fast, we might terminate ourselves. | |
proc.WaitForExit(); | |
//Re-enable Ctrl-C handling or any subsequently started | |
//programs will inherit the disabled state. | |
// SetConsoleCtrlHandler(null, false); | |
} | |
static void Main(string[] args) | |
{ | |
// start an application | |
if (args.Length == 1) | |
{ | |
child(); | |
} | |
else | |
{ | |
parent(); | |
} | |
} | |
private static void parent() | |
{ | |
var location = System.Reflection.Assembly.GetExecutingAssembly().Location; | |
var process = new Process() | |
{ | |
StartInfo = new ProcessStartInfo() | |
{ | |
FileName = location, | |
Arguments = "child", | |
UseShellExecute = false, | |
}, | |
}; | |
process.Start(); | |
Thread.Sleep(1000); | |
// NOTE: if UseShellExecute isn't false, then the child process | |
// will get it's own console and the parent will have to Dettach | |
// from its own console and attach to the child's. This is accomplished | |
// by the following code. Note that We can't | |
// attach to multiple consoles and we have to be attached to | |
// some console otherwise ReadLine() will throw an exception (code starts here): | |
// FreeConsole(); | |
// AttachConsole((uint)process.Id); | |
// Set the parent console handler so we don't die when a Ctrl-C event | |
// is received. NOTE: the following call can be replaced with | |
// Console.CancelKeyPress See https://msdn.microsoft.com/en-us/library/system.console.cancelkeypress%28v=vs.110%29.aspx | |
SetConsoleCtrlHandler(ParentConsoleCtrlCheck, true); | |
while (true) | |
{ | |
Console.WriteLine("parent: started"); | |
var line = Console.ReadLine(); | |
if (line == "t") | |
{ | |
StopProgram(process); | |
} | |
else if (line == "k") | |
{ | |
process.Kill(); | |
} | |
else | |
{ | |
continue; | |
} | |
while (true) | |
{ | |
// the parent will display this when the child dies | |
Console.WriteLine("parent: child is dead"); | |
Thread.Sleep(1000); | |
} | |
} | |
} | |
private static void child() | |
{ | |
// NOTE: the following call can be replaced with | |
// Console.CancelKeyPress See https://msdn.microsoft.com/en-us/library/system.console.cancelkeypress%28v=vs.110%29.aspx | |
SetConsoleCtrlHandler(ChildConsoleCtrlCheck, true); | |
while (true) | |
{ | |
Thread.Sleep(1000); | |
// The child will stop printing this when it dies | |
Console.WriteLine("child: waiting"); | |
} | |
} | |
private static bool ChildConsoleCtrlCheck(CtrlTypes sig) | |
{ | |
Console.WriteLine("child: Received shutdown event"); | |
// Returning false, will cause the default event handler | |
// to run and kill the child process | |
return false; | |
} | |
private static bool ParentConsoleCtrlCheck(CtrlTypes sig) | |
{ | |
Console.WriteLine("parent: Received shutdown event"); | |
// Returning true prevents the default handler from running | |
// which kills the parent | |
return true; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment