【问题标题】:Unable to trap Ctrl+C in a C# console app无法在 C# 控制台应用程序中捕获 Ctrl+C
【发布时间】:2024-01-30 08:35:02
【问题描述】:

我尝试使用以下代码在控制台应用程序中捕获 Ctrl+C:

    /// <summary>
    /// A driver program for testing 
    /// </summary>
    /// <param name="args">Arguments to the program</param>
    static void Main(string[] args)
    {
        var program = new Program();

        Console.Clear();
        Console.TreatControlCAsInput = false;
        Console.CancelKeyPress += program.OnCancelKeyPress;

        program.Run(args.FirstOrDefault() ?? "3.26.200.125");

        Console.WriteLine("Press any key to continue ...");
        Console.ReadKey();
    }

    /// <summary>
    /// Called when [cancel key press].
    /// </summary>
    /// <param name="sender">The sender.</param>
    /// <param name="e">The <see cref="System.ConsoleCancelEventArgs"/> instance containing the event data.</param>
    internal void OnCancelKeyPress(object sender, ConsoleCancelEventArgs e)
    {
        this.Continue = false;
        e.Cancel = true;
    }

我已经检查了herehere 的问题,但是由于某种原因,当我按下 Control+C 时,Visual Studio 2010 不会进入调试器中的处理程序,我只是得到一个“源”代码不可用”屏幕,以及继续调试的机会,仅此而已。有人知道我为什么不进入处理程序吗?我确定我只是缺少一些简单的东西。

【问题讨论】:

  • 这也是我调试的时候,当我在 release 中运行程序时它工作正常。这只是我遇到的视觉工作室问题吗?
  • 您是否尝试过在控制处理程序中设置断点?在您的处理程序运行之前,可能有一些原因导致 Visual Studio 中断执行。然后您可以查看是否继续稍后进入控制处理程序。
  • 是的,我在处理程序中放置了一个断点,它永远不会被命中。一旦我在上面提到的点按 F5 继续(希望进入我的处理程序),程序就会恢复运行,就好像什么都没发生,也没有按下中断键。
  • 由于调试器的更改而为 VS2010 设计。 Ctrl+C 现在的作用类似于 Debug + Break All。一种解决方法是启用非托管代码调试,单击消息框上的继续,您的断点将被命中。

标签: c# console interrupt-handling


【解决方案1】:

当 Main 退出时,您使用 Console.CancelKeyPress += program.OnCancelKeyPress 注册的事件处理程序会被垃圾回收。然后,当操作系统尝试访问委托时,就没有代码可以运行了。

您必须声明一个静态委托以在Main 的范围之外运行,然后在Main 内分配它,以便在操作系统尝试回调它时它保持在范围内。

【讨论】:

  • 显然不是这样,因为当我不在 Visual Studio 中调试时,处理程序运行良好。
  • 你是对的。我提供的答案是在我通过 Windows API 调用而不是您上面显示的方法注册 Ctrl-C 处理程序时工作的。看起来你已经明白了,所以这是个好消息。
【解决方案2】:

显然有一个bug 来自Connect 页面的解决方法是:

同时,要解决此问题,您可以启用混合模式调试。然后,当您按下 Ctrl-C 并弹出一个对话框,通知您第一次出现 Ctrl-C 异常时,单击“继续”。然后,您应该在处理程序中点击断点。

【讨论】:

  • 你是对的。我启用了混合模式调试,它现在进入了处理程序。非常感谢。
【解决方案3】:

下面的代码很适合我

using System;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Clear();
            Console.WriteLine("Press X to quit");
            Console.TreatControlCAsInput = false;
            Console.CancelKeyPress += (s, ev) =>
                                          {
                                              Console.WriteLine("Ctrl+C pressed");
                                              ev.Cancel = true;
                                          };

            while (true)
                if (Console.ReadKey().Key == ConsoleKey.X)
                    break;
        }
    }
}

希望这会有所帮助!

【讨论】:

  • 坏主意! ReadKey() 将阻塞并且不应该以任何典型的方式这样做。尝试考虑使用 CancellationToken 并将其放入自己的线程/任务中,并在它们之间进行检查点和同步。您也可以尝试使用 Console.KeyAvailable 属性进行轮询。当它返回 True 时,ReadKey() 不会阻塞。
  • 是的,但重点不是证明这一点。只需捕获Ctrl + C。另外:你试过了吗?作为一个简单的示例,它按预期工作。
  • 是的,我正在研究一些非常相似的东西,并在我们说话的时候对其进行测试。然而,我的更复杂,因为我添加了异步的东西,使其成为非阻塞 w/取消等。
最近更新 更多