You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

C#实现进程退出时执行代码及跨进程关闭的问题

我来帮你解决这个问题!你需要让第一个应用在被第二个应用关闭时执行指定的退出代码,这里分几种场景来处理,因为不同的关闭方式会影响退出代码的执行逻辑:

解决方案:让第一个应用在退出时执行指定代码

1. 处理正常退出场景(主动关闭、外部发送关闭信号)

如果第二个应用是通过正常方式关闭第一个应用(比如关闭主窗口、发送退出信号),我们可以通过注册.NET的退出事件来捕获退出时机,执行你的DoSomethingOnExit方法。

修改第一个应用的代码:

using System;
using System.Threading;

public class First
{
    public static void Main(string[] args)
    {
        // 注册进程退出事件:当进程正常终止时触发
        AppDomain.CurrentDomain.ProcessExit += (sender, e) =>
        {
            DoSomethingOnExit();
        };

        // 注册控制台关闭事件:处理用户关闭控制台窗口、Ctrl+C等场景
        Console.CancelKeyPress += (sender, e) =>
        {
            DoSomethingOnExit();
            // 设置Cancel=true,让进程正常退出而不是立即终止
            e.Cancel = true;
        };

        Console.WriteLine("第一个应用已启动,按Enter退出或等待第二个应用关闭...");
        Console.ReadLine();
    }

    // 把方法改为static,方便在静态事件处理中调用;如果需要实例方法,也可以先实例化First再调用
    public static void DoSomethingOnExit()
    {
        Console.WriteLine("It Works");
        Thread.Sleep(1000);
    }
}

第二个应用的关闭代码(正常关闭):

如果第一个应用是控制台程序,CloseMainWindow()可能无法直接触发退出(因为控制台程序在Console.ReadLine()时阻塞),所以可以尝试先发送信号,或者等待用户输入的逻辑结束。如果是带UI的应用,CloseMainWindow()会更有效:

using System.Diagnostics;

public class Second
{
    public void CloseFirstApp(int processId)
    {
        try
        {
            var targetProcess = Process.GetProcessById(processId);
            
            // 尝试正常关闭主窗口(适用于UI程序,控制台程序可能需要其他方式)
            if (targetProcess.CloseMainWindow())
            {
                // 等待进程退出
                targetProcess.WaitForExit();
                Console.WriteLine("第一个应用已正常关闭,退出代码已执行");
            }
            else
            {
                // 正常关闭失败,降级为强制终止(这种情况退出代码不会执行)
                targetProcess.Kill();
                Console.WriteLine("第一个应用无法正常关闭,已强制终止");
            }
        }
        catch (ArgumentException)
        {
            Console.WriteLine("未找到目标进程");
        }
    }
}

2. 处理强制终止场景(第二个应用用Kill()关闭第一个)

如果第二个应用必须用Process.Kill()强制终止第一个应用,那么.NET的退出事件(ProcessExitCancelKeyPress)都不会触发,因为Kill()会立即终止进程,不给执行退出代码的机会。这种情况下,我们需要让两个应用之间建立通信,让第一个应用收到关闭通知后主动执行退出代码再退出。

用命名管道实现优雅关闭(推荐)

第一个应用代码:

using System;
using System.IO.Pipes;
using System.Threading;
using System.Threading.Tasks;

public class First
{
    private static bool _shouldExit = false;

    public static void Main(string[] args)
    {
        // 启动后台任务监听关闭信号
        _ = Task.Run(ListenForCloseSignal);

        Console.WriteLine("第一个应用已启动,等待关闭信号或按Enter退出...");
        while (!_shouldExit)
        {
            // 检查用户是否按Enter退出
            if (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Enter)
            {
                _shouldExit = true;
            }
            Thread.Sleep(100);
        }

        // 退出前执行代码
        DoSomethingOnExit();
    }

    private static void ListenForCloseSignal()
    {
        // 创建命名管道服务器,监听来自第二个应用的信号
        using var pipeServer = new NamedPipeServerStream("FirstAppClosePipe", PipeDirection.InOut);
        pipeServer.WaitForConnection();

        // 收到关闭信号,标记退出
        _shouldExit = true;
    }

    public static void DoSomethingOnExit()
    {
        Console.WriteLine("It Works");
        Thread.Sleep(1000);
    }
}

第二个应用代码:

using System.IO.Pipes;
using System.Diagnostics;

public class Second
{
    public void GracefullyCloseFirstApp(int processId)
    {
        try
        {
            var targetProcess = Process.GetProcessById(processId);
            
            // 连接到第一个应用的命名管道,发送关闭信号
            using var pipeClient = new NamedPipeClientStream(".", "FirstAppClosePipe", PipeDirection.InOut);
            pipeClient.Connect(5000); // 等待5秒连接超时

            // 等待第一个应用执行退出代码并退出
            targetProcess.WaitForExit();
            Console.WriteLine("第一个应用已优雅关闭,退出代码已执行");
        }
        catch (ArgumentException)
        {
            Console.WriteLine("未找到目标进程");
        }
        catch (TimeoutException)
        {
            // 连接失败,强制终止
            var targetProcess = Process.GetProcessById(processId);
            targetProcess.Kill();
            Console.WriteLine("无法与第一个应用通信,已强制终止");
        }
    }
}

关键注意点:

  • 如果必须用Process.Kill()没有办法让第一个应用执行退出代码,因为Kill是操作系统强制终止进程,进程没有机会执行任何代码。所以尽量使用优雅关闭的方式。
  • 控制台程序的CloseMainWindow()效果有限,因为控制台程序的消息循环和UI程序不同,所以用命名管道或其他IPC方式更可靠。

内容的提问来源于stack exchange,提问作者Homer Tw

火山引擎 最新活动