Example #1
0
        public static async Task <bool> TrySignalAsync(int processId, NativeMethods.CtrlType signal)
        {
            if (HasSameConsole(processId))
            {
                return(await SendSignalFromCurrentProcess(processId, signal).ConfigureAwait(false));
            }

            using (var file = await DeploySignalerExeAsync().ConfigureAwait(false))
            {
                var command = Command.Run(file.Path, new object[] { processId, (int)signal });
                return((await command.Task.ConfigureAwait(false)).Success);
            }
        }
        private static async Task <bool> SendSignalFromCurrentProcess(int processId, NativeMethods.CtrlType signal)
        {
            await SignalFromCurrentProcessLock.WaitAsync().ConfigureAwait(false);

            try
            {
                using (var waitForSignalSemaphore = new SemaphoreSlim(initialCount: 0, maxCount: 1))
                {
                    NativeMethods.ConsoleCtrlDelegate handler = receivedSignal =>
                    {
                        if (receivedSignal == signal)
                        {
                            waitForSignalSemaphore.Release();
                            // if we're signaling another process on the same console, we return true
                            // to prevent the signal from bubbling. If we're signaling ourselves, we
                            // allow it to bubble since presumably that's what the caller wanted
                            return(processId != ProcessHelper.CurrentProcessId);
                        }
                        return(false);
                    };
                    if (!NativeMethods.SetConsoleCtrlHandler(handler, add: true))
                    {
                        Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                    }
                    try
                    {
                        if (!NativeMethods.GenerateConsoleCtrlEvent(signal, NativeMethods.AllProcessesWithCurrentConsoleGroup))
                        {
                            return(false);
                        }

                        // Wait until the signal has reached our handler and been handled to know that it is safe to
                        // remove the handler.
                        // Timeout here just to ensure we don't hang forever if something weird happens (e. g. someone
                        // else registers a handler concurrently with us).
                        return(await waitForSignalSemaphore.WaitAsync(TimeSpan.FromSeconds(30)).ConfigureAwait(false));
                    }
                    finally
                    {
                        if (!NativeMethods.SetConsoleCtrlHandler(handler, add: false))
                        {
                            Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
                        }
                    }
                }
            }
            finally
            {
                SignalFromCurrentProcessLock.Release();
            }
        }
Example #3
0
        private static bool Handler(NativeMethods.CtrlType sig)
        {
            Console.WriteLine("Stopping due to external CTRL-C, or process kill, or shutdown");

            if (_ctsSource != null)
            {
                _ctsSource.Cancel();
            }

            Thread.Sleep(500);

            //shutdown right away so there are no lingering threads
            Environment.Exit(0);

            return(true);
        }
Example #4
0
        // implementation based on https://stackoverflow.com/questions/813086/can-i-send-a-ctrl-c-sigint-to-an-application-on-windows
        // + some additional research / experimentation

        public static int Signal(int processId, NativeMethods.CtrlType ctrlType)
        {
            // first detach from the current console if one exists. We don't check the exit
            // code since the only documented fail case is not having a console
            NativeMethods.FreeConsole();

            // attach to the child's console
            return(NativeMethods.AttachConsole(checked ((uint)processId))
                   // disable signal handling for our program
                   // from https://docs.microsoft.com/en-us/windows/console/setconsolectrlhandler:
                   // "Calling SetConsoleCtrlHandler with the NULL and TRUE arguments causes the calling process to ignore CTRL+C signals"
                   && NativeMethods.SetConsoleCtrlHandler(null, true)
                   // send the signal
                   && NativeMethods.GenerateConsoleCtrlEvent(ctrlType, NativeMethods.AllProcessesWithCurrentConsoleGroup)
                    ? 0
                    : Marshal.GetLastWin32Error());
        }
Example #5
0
 private static bool Handler(NativeMethods.CtrlType sig)
 {
     _container.Dispose();
     return(false);
 }
Example #6
0
 public virtual void Exit(NativeMethods.CtrlType ctrlType)
 {
 }
Example #7
0
 void OnExit(NativeMethods.CtrlType ctrlType)
 {
     Running = false;
     Thread.Sleep(1000);
     Exit(ctrlType);
 }