diff --git a/Main.cs b/Main.cs
index d7dd5b4..9ca2884 100644
--- a/Main.cs
+++ b/Main.cs
@@ -340,7 +340,25 @@ namespace winsw
try
{
var proc = Process.GetProcessById(pid);
- proc.Kill();
+ if (descriptor.SendSIGINT)
+ {
+ WriteEvent("Send SIGINT " + process.Id);
+ bool successful = SigIntHelper.SendSIGINTToProcess(proc);
+ if (successful)
+ {
+ WriteEvent("SIGINT to" + process.Id + " successful");
+ }
+ else
+ {
+ WriteEvent("SIGINT to " + process.Id + " failed - Killing as fallback");
+ proc.Kill();
+ }
+ }
+ else
+ {
+ WriteEvent("ProcessKill " + process.Id);
+ proc.Kill();
+ }
}
catch (ArgumentException)
{
diff --git a/ServiceDescriptor.cs b/ServiceDescriptor.cs
index 7453a54..937cb54 100755
--- a/ServiceDescriptor.cs
+++ b/ServiceDescriptor.cs
@@ -561,5 +561,15 @@ namespace winsw
return !string.IsNullOrEmpty(serviceAccountDomain) && !string.IsNullOrEmpty(serviceAccountName);
}
+ ///
+ /// True if the service can interact with the desktop.
+ ///
+ public bool SendSIGINT
+ {
+ get
+ {
+ return dom.SelectSingleNode("//sendsigint") != null;
+ }
+ }
}
}
diff --git a/SigIntHelper.cs b/SigIntHelper.cs
new file mode 100644
index 0000000..3378d09
--- /dev/null
+++ b/SigIntHelper.cs
@@ -0,0 +1,62 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace winsw
+{
+ public static class SigIntHelper
+ {
+ private const string KERNEL32 = "kernel32.dll";
+
+ [DllImport(KERNEL32, SetLastError = true)]
+ private static extern bool AttachConsole(uint dwProcessId);
+
+ [DllImport(KERNEL32, SetLastError = true, ExactSpelling = true)]
+ private static extern bool FreeConsole();
+
+ [DllImport(KERNEL32)]
+ private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate HandlerRoutine, bool Add);
+ // Delegate type to be used as the Handler Routine for SCCH
+ private delegate Boolean ConsoleCtrlDelegate(CtrlTypes CtrlType);
+
+ // Enumerated type for the control messages sent to the handler routine
+ private enum CtrlTypes : uint
+ {
+ CTRL_C_EVENT = 0,
+ CTRL_BREAK_EVENT,
+ CTRL_CLOSE_EVENT,
+ CTRL_LOGOFF_EVENT = 5,
+ CTRL_SHUTDOWN_EVENT
+ }
+
+ [DllImport(KERNEL32)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);
+
+ ///
+ /// Uses the native funciton "AttachConsole" to attach the thread to the executing process to try to trigger a CTRL_C event (SIGINT). If the application
+ /// doesn't honor the event and shut down gracefully, the. wait period will time out after 15 seconds.
+ ///
+ /// The process to attach to and send the SIGINT
+ /// True if the process shut down successfully to the SIGINT, false if it did not.
+ public static bool SendSIGINTToProcess(Process process)
+ {
+ if (AttachConsole((uint)process.Id))
+ {
+ //Disable Ctrl-C handling for our program
+ SetConsoleCtrlHandler(null, true);
+ GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
+
+ process.WaitForExit(15000);
+
+ return process.HasExited;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/winsw.csproj b/winsw.csproj
index cfbb8db..0355d39 100644
--- a/winsw.csproj
+++ b/winsw.csproj
@@ -3,7 +3,7 @@
Debug
AnyCPU
- 9.0.21022
+ 9.0.30729
2.0
{0DE77F55-ADE5-43C1-999A-0BC81153B039}
Exe
@@ -56,6 +56,7 @@
+