windows - 我可以向 Windows 上的应用程序发送 ctrl-C (SIGINT) 吗?

标签 windows signals sigint

我(过去)编写了跨平台(Windows/Unix)应用程序,当从命令行启动时,处理用户键入的 Ctrl-C 以相同的方式组合(即干净地终止应用程序)。

是否有可能在 Windows 上从另一个(不相关的)进程发送一个 Ctrl-C/SIGINT/等同于一个进程来请求它干净地终止(给它整理资源等的机会)?

最佳答案

我围绕这个主题做了一些研究,结果比我预期的更受欢迎。 KindDragon 的回复是关键点之一。

我写了一个longer blog post关于这个主题并创建了一个工作演示程序,它演示了使用这种类型的系统以几种不错的方式关闭命令行应用程序。该帖子还列出了我在研究中使用的外部链接。

简而言之,这些演示程序执行以下操作:

  • 使用 .Net 启动带有可见窗口的程序,使用 pinvoke 隐藏,运行 6 秒,使用 pinvoke 显示,停止.Net.
  • 使用 .Net 启动一个没有窗口的程序,运行 6 秒,通过附加控制台并发出 ConsoleCtrlEvent
  • 停止

编辑:来自@KindDragon 的修改后的解决方案,适用于那些对此时此地的代码感兴趣的人。如果您打算在停止第一个程序后启动其他程序,您应该重新启用CTRL+C 处理,否则下一个进程将继承父进程的禁用状态而不会响应CTRL+C

[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 HandlerRoutine, bool Add);

delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);

// 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 void StopProgram(Process proc)
{
    //This does not require the console window to be visible.
    if (AttachConsole((uint)proc.Id))
    {
    // Disable Ctrl-C handling for our program
    SetConsoleCtrlHandler(null, true); 
    GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);

    //Moved this command up on suggestion from Timothy Jannace (see comments below)
    FreeConsole();
                
    // Must wait here. If we don't and re-enable Ctrl-C
    // handling below too fast, we might terminate ourselves.
    proc.WaitForExit(2000);
                
    //Re-enable Ctrl-C handling or any subsequently started
    //programs will inherit the disabled state.
    SetConsoleCtrlHandler(null, false); 
    }
}

此外,如果 AttachConsole() 或发送的信号失败,请计划一个应急解决方案,例如 sleep ,然后这个:

if (!proc.HasExited)
{
    try
    {
    proc.Kill();
    }
    catch (InvalidOperationException e){}
}

关于windows - 我可以向 Windows 上的应用程序发送 ctrl-C (SIGINT) 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/813086/

相关文章:

c - 忽略 ctrl-c

Windows 批处理 : formatted date into variable

django - 在哪里放置 django 信号接收器代码,将它们分布在多个文件中?

c - C 中的信号处理

android - 如何在 Android 中获取手机服务信号强度?

c - 简单 shell 中的段错误

python - 为什么我的线程/多处理 python 脚本没有正常退出?

windows - Dos 提示符 - 仅在出错时暂停执行/显示?

windows - 如何在 Windows Server 2008 R2 中关闭(禁用)Web 代理自动发现 (WPAD)

mysql - 如何在cmd Windows中运行Mysql 5.7