From 9d057a05e3aff579f729c5ab73c30f5123c9b2e7 Mon Sep 17 00:00:00 2001 From: Mehdi Gholam Date: Sat, 28 Sep 2024 15:41:40 +0330 Subject: [PATCH] Update Program.cs - sets working directory to the exe path - sends ctrl+c for graceful shutdown --- RunAsService/Program.cs | 59 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 2 deletions(-) diff --git a/RunAsService/Program.cs b/RunAsService/Program.cs index f2e4af2..44e0f85 100644 --- a/RunAsService/Program.cs +++ b/RunAsService/Program.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Text; @@ -7,6 +7,7 @@ using System.Reflection; using System.Diagnostics; using System.ServiceProcess; +using System.Threading; namespace RunAsService { class RunAsService { @@ -518,14 +519,68 @@ protected override void OnStart(string[] args) { CreateNoWindow = true, ErrorDialog = false, WindowStyle = ProcessWindowStyle.Hidden, + WorkingDirectory = Path.GetDirectoryName(consoleApplicationExecutablePath) }; process = Process.Start(oProcessStartInfo); } protected override void OnStop() { - process.Kill(); + // send ctrl+c to process for graceful shutdown + StopProgram((uint)process.Id); + if (!process.HasExited) process.Kill(); process = null; } + + [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")] + static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate handler, bool add); + + // Delegate type to be used as the Handler Routine for SCCH + delegate Boolean ConsoleCtrlDelegate(CtrlTypes type); + + // Enumerated type for the control messages sent to the handler routine + enum CtrlTypes : uint + { + CTRL_C_EVENT = 0, + CTRL_BREAK_EVENT, + CTRL_CLOSE_EVENT, + CTRL_LOGOFF_EVENT = 5, + CTRL_SHUTDOWN_EVENT + } + + [DllImport("kernel32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId); + + public static void StopProgram(uint pid) + { + // It's impossible to be attached to 2 consoles at the same time, + // so release the current one. + FreeConsole(); + + // This does not require the console window to be visible. + if (AttachConsole(pid)) + { + // 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. + Thread.Sleep(2000); + + FreeConsole(); + + // Re-enable Ctrl-C handling or any subsequently started + // programs will inherit the disabled state. + SetConsoleCtrlHandler(null, false); + } + } } }