internal ControlCDelegateData(ConsoleSpecialKey controlKey, ConsoleCancelEventHandler cancelCallbacks) { this.ControlKey = controlKey; this.CancelCallbacks = cancelCallbacks; this.CompletionEvent = new ManualResetEvent(false); // this.Cancel defaults to false // this.DelegateStarted defaults to false }
public void InvalidEnumValue() { const ConsoleSpecialKey invalidValue = (ConsoleSpecialKey)15; Action act = () => invalidValue.MustBeValidEnumValue(nameof(invalidValue)); act.ShouldThrow <EnumValueNotDefinedException>() .And.ParamName.Should().Be(nameof(invalidValue)); }
protected override bool OnCancelKeySignal(ConsoleSpecialKey consoleSpecialKey) { if (consoleSpecialKey == ConsoleSpecialKey.ControlC) { this.CancellationTokenSource.Cancel(); return(true); } return(base.OnCancelKeySignal(consoleSpecialKey)); }
public static void InvalidEnumValue() { const ConsoleSpecialKey invalidValue = (ConsoleSpecialKey)15; Action act = () => invalidValue.MustBeValidEnumValue(nameof(invalidValue)); var exceptionAssertion = act.Should().Throw <EnumValueNotDefinedException>().Which; exceptionAssertion.Message.Should().Contain($"{nameof(invalidValue)} \"{invalidValue}\" must be one of the defined constants of enum \"{invalidValue.GetType()}\", but it actually is not."); exceptionAssertion.ParamName.Should().Be(nameof(invalidValue)); }
internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey) { ConsoleCancelEventHandler handler = s_cancelCallbacks; if (handler == null) { return(false); } var args = new ConsoleCancelEventArgs(controlKey); handler(null, args); return(args.Cancel); }
private void CloseConsole(ConsoleSpecialKey closeKey, int forceCloseMillisecondsTimeout) { try { if (_process == null || _process.HasExited) { return; } Trace.TraceInformation("Closing app input by sending Ctrl-Z signal"); _process.StandardInput.Close(); if (_process == null || _process.HasExited) { return; } Trace.TraceInformation("Trying to close the app gracefully by sending " + closeKey); Win32.AttachConsole((uint)_process.Id); Win32.SetConsoleCtrlHandler(_consoleCtrlEventHandler, true); var ctrlType = closeKey == ConsoleSpecialKey.ControlC ? Win32.CtrlType.CtrlCEvent : Win32.CtrlType.CtrlBreakEvent; Win32.GenerateConsoleCtrlEvent(ctrlType, 0); if (_process == null || _process.HasExited) { return; } // close console forcefully if not finished within allowed timeout Trace.TraceInformation("Waiting for voluntary app exit: Timeout={0}", forceCloseMillisecondsTimeout); var exited = _process.WaitForExit(forceCloseMillisecondsTimeout); if (!exited) { Trace.TraceWarning("Closing the app forcefully"); _process.Kill(); } } catch (Exception) { try { Process.GetProcessById(ProcessID).Kill(); } catch { } } finally { FreeProcessResources(); GC.Collect(); GC.SuppressFinalize(this); } }
// Method that is called to handle "cancel" events. private static void HandleCancel(ConsoleSpecialKey specialKeys) { ConsoleCancelEventArgs args; args = new ConsoleCancelEventArgs(specialKeys); if (CancelKeyPress != null) { CancelKeyPress(null, args); } if (!(args.Cancel)) { NormalMode(); Environment.Exit(1); } }
public static void InvalidEnumValueWithCustomParameterizedException() { const ConsoleSpecialKey invalidValue = (ConsoleSpecialKey)15; var observedValue = default(ConsoleSpecialKey); var exception = new Exception(); Action act = () => invalidValue.MustBeValidEnumValue(v => { observedValue = v; return(exception); }); act.Should().Throw <Exception>().Which.Should().BeSameAs(exception); observedValue.Should().Be(invalidValue); }
// Returns true if we've "handled" the break request, false if // we want to terminate the process (or at least let the next // control handler function have a chance). private static bool BreakEvent(int controlType) { // The thread that this gets called back on has a very small stack on 64 bit systems. There is // not enough space to handle a managed exception being caught and thrown. So, queue up a work // item on another thread for the actual event callback. if (controlType == Win32Native.CTRL_C_EVENT || controlType == Win32Native.CTRL_BREAK_EVENT) { // To avoid race between remove handler and raising the event ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks; if (cancelCallbacks == null) { return(false); } // Create the delegate ConsoleSpecialKey controlKey = (controlType == 0) ? ConsoleSpecialKey.ControlC : ConsoleSpecialKey.ControlBreak; ControlCDelegateData delegateData = new ControlCDelegateData(controlKey, cancelCallbacks); WaitCallback controlCCallback = new WaitCallback(ControlCDelegate); // Queue the delegate if (!ThreadPool.QueueUserWorkItem(controlCCallback, delegateData)) { BCLDebug.Assert(false, "ThreadPool.QueueUserWorkItem returned false without throwing. Unable to execute ControlC handler"); return(false); } // Block until the delegate is done. We need to be robust in the face of the work item not executing // but we also want to get control back immediately after it is done and we don't want to give the // handler a fixed time limit in case it needs to display UI. Wait on the event twice, once with a // timout and a second time without if we are sure that the handler actually started. TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds delegateData.CompletionEvent.WaitOne(controlCWaitTime, false); if (!delegateData.DelegateStarted) { BCLDebug.Assert(false, "ThreadPool.QueueUserWorkItem did not execute the handler within 30 seconds."); return(false); } delegateData.CompletionEvent.WaitOne(); delegateData.CompletionEvent.Close(); return(delegateData.Cancel); } return(false); }
} // Real main() #region CtrlC-Handler // Now set the handler and do the processing // void CtrlCHandler(object sender, ConsoleCancelEventArgs args) { Sup.LogDebugMessage("SensorArray Gracefull exit... Begin"); ConsoleSpecialKey Key = args.SpecialKey; //Sup.LogDebugMessage($"Key Pressed: {Key}"); //Console.WriteLine($"Key Pressed: {Key}"); switch (Key) { // Maybe some time I do a Signal base dynamic errorlevel setting // but ctrl-break does not work on my machine case ConsoleSpecialKey.ControlBreak: // Look at the end of the file for what I thought to do here if the button worked. // For now, let go. // Do not immedialtely stop the process. args.Cancel = true; break; case ConsoleSpecialKey.ControlC: for (int i = 0; i < MaxNrI2cSensors; i++) { thisI2C[i].Stop(); } for (int i = 0; i < MaxNrSerialSensors; i++) { thisSerial[i].Stop(); } if (AirLinkEmulation) { thisWebserver.Stop(); } args.Cancel = true; // Do not immedialtely stop the process, handle it by the Continue loop control boolean. Continue = false; break; default: // Should be impossible break; } return; }
internal static bool HandleBreakEvent(ConsoleSpecialKey controlKey) { // The thread that this gets called back on has a very small stack on some systems. There is // not enough space to handle a managed exception being caught and thrown. So, run a task // on the threadpool for the actual event callback. // To avoid the race condition between remove handler and raising the event ConsoleCancelEventHandler cancelCallbacks = Console._cancelCallbacks; if (cancelCallbacks == null) { return(false); } var delegateData = new ControlCDelegateData(controlKey, cancelCallbacks); Task callBackTask = Task.Factory.StartNew( d => ((ControlCDelegateData)d).HandleBreakEvent(), delegateData, CancellationToken.None, TaskCreationOptions.DenyChildAttach, TaskScheduler.Default); // Block until the delegate is done. We need to be robust in the face of the task not executing // but we also want to get control back immediately after it is done and we don't want to give the // handler a fixed time limit in case it needs to display UI. Wait on the task twice, once with a // timeout and a second time without if we are sure that the handler actually started. TimeSpan controlCWaitTime = new TimeSpan(0, 0, 30); // 30 seconds callBackTask.Wait(controlCWaitTime); if (!delegateData.DelegateStarted) { Debug.Assert(false, "The task to execute the handler did not start within 30 seconds."); return(false); } callBackTask.Wait(); return(delegateData.Cancel); }
/// <summary> /// Stop the app. /// </summary> /// <param name="closeKey">Special key to send to close the app [default=Ctrl-C]</param> /// <param name="forceCloseMillisecondsTimeout">Timeout to wait before closing the app forcefully [default=infinite]</param> public void Stop(ConsoleSpecialKey closeKey = ConsoleSpecialKey.ControlC, int forceCloseMillisecondsTimeout = Timeout.Infinite) { ThrowIfDisposed(); lock (_stateLock) { if (State == AppState.Undefined || State == AppState.Exited) { throw new InvalidOperationException("App is not running."); } if (State == AppState.Exiting) { throw new InvalidOperationException("App is already exiting."); } State = AppState.Exiting; Task.Factory.StartNew(() => CloseConsole(closeKey, forceCloseMillisecondsTimeout), TaskCreationOptions.LongRunning); } }
private void CloseConsole(ConsoleSpecialKey closeKey, int forceCloseMillisecondsTimeout) { if (Process == null || Process.HasExited) { return; } Trace.TraceInformation("Closing app input by sending Ctrl-Z signal"); Process.StandardInput.Close(); if (Process == null || Process.HasExited) { return; } Trace.TraceInformation("Trying to close the app gracefully by sending " + closeKey); Win32.AttachConsole((uint)Process.Id); Win32.SetConsoleCtrlHandler(_consoleCtrlEventHandler, true); var ctrlType = closeKey == ConsoleSpecialKey.ControlC ? Win32.CtrlType.CtrlCEvent : Win32.CtrlType.CtrlBreakEvent; Win32.GenerateConsoleCtrlEvent(ctrlType, 0); if (Process == null || Process.HasExited) { return; } // close console forcefully if not finished within allowed timeout Trace.TraceInformation("Waiting for voluntary app exit: Timeout={0}", forceCloseMillisecondsTimeout); var exited = Process.WaitForExit(forceCloseMillisecondsTimeout); if (!exited) { Trace.TraceWarning("Closing the app forcefully"); Process.Kill(); } }
// Method that is called to handle "cancel" events. private static void HandleCancel(ConsoleSpecialKey specialKeys) { ConsoleCancelEventArgs args; args = new ConsoleCancelEventArgs(specialKeys); if(CancelKeyPress != null) { CancelKeyPress(null, args); } if(!(args.Cancel)) { NormalMode(); Environment.Exit(1); } }
internal ControlCDelegateData(ConsoleSpecialKey controlKey, ConsoleCancelEventHandler cancelCallbacks) { _controlKey = controlKey; _cancelCallbacks = cancelCallbacks; }
private bool _cancel; // Whether to cancel the CancelKeyPress event internal ConsoleCancelEventArgs(ConsoleSpecialKey type) { _type = type; _cancel = false; }
} // 0x00000001802D2B60-0x00000001802D2B70 // Constructors internal ConsoleCancelEventArgs(ConsoleSpecialKey type) { } // 0x000000018080FAB0-0x000000018080FB20
internal ConsoleCancelEventArgs(ConsoleSpecialKey type) { _type = type; }
// Constructor. internal ConsoleCancelEventArgs(ConsoleSpecialKey specialKey) { this.cancel = false; this.specialKey = specialKey; }
internal ConsoleCancelEventArgs(ConsoleSpecialKey type) { this._type = type; this._cancel = false; }
internal ConsoleCancelEventArgs (ConsoleSpecialKey key) { specialKey = key; }
internal ConsoleCancelEventArgs(ConsoleSpecialKey key) { specialKey = key; }
/// <summary> /// Stop the app. /// </summary> /// <param name="closeKey">Special key to send to close the app [default=Ctrl-C]</param> /// <param name="forceCloseMillisecondsTimeout">Timeout to wait before closing the app forcefully [default=infinite]</param> public void Stop(ConsoleSpecialKey closeKey = ConsoleSpecialKey.ControlC, int forceCloseMillisecondsTimeout = Timeout.Infinite) { ThrowIfDisposed(); lock (_stateLock) { if (State == AppState.Undefined || State == AppState.Exited) throw new InvalidOperationException("App is not running."); if (State == AppState.Exiting) throw new InvalidOperationException("App is already exiting."); State = AppState.Exiting; Task.Factory.StartNew(() => CloseConsole(closeKey, forceCloseMillisecondsTimeout), TaskCreationOptions.LongRunning); } }
private void CloseConsole(ConsoleSpecialKey closeKey, int forceCloseMillisecondsTimeout) { if (_process == null || _process.HasExited) return; Trace.TraceInformation("Closing app input by sending Ctrl-Z signal"); _process.StandardInput.Close(); if (_process == null || _process.HasExited) return; Trace.TraceInformation("Trying to close the app gracefully by sending " + closeKey); Win32.AttachConsole((uint)_process.Id); Win32.SetConsoleCtrlHandler(_consoleCtrlEventHandler, true); var ctrlType = closeKey == ConsoleSpecialKey.ControlC ? Win32.CtrlType.CtrlCEvent : Win32.CtrlType.CtrlBreakEvent; Win32.GenerateConsoleCtrlEvent(ctrlType, 0); if (_process == null || _process.HasExited) return; // close console forcefully if not finished within allowed timeout Trace.TraceInformation("Waiting for voluntary app exit: Timeout={0}", forceCloseMillisecondsTimeout); var exited = _process.WaitForExit(forceCloseMillisecondsTimeout); if (!exited) { Trace.TraceWarning("Closing the app forcefully"); _process.Kill(); } }
/// <summary> /// The event handler for this event is executed on a thread pool thread. /// </summary> /// <param name="consoleSpecialKey"> </param> /// <returns> </returns> protected virtual bool OnCancelKeySignal(ConsoleSpecialKey consoleSpecialKey) { return(false); }