首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> C# >> 關於C#

C# 捕獲主控台關閉事件:SetConsoleCtrlHandler 完整實作

     編輯:關於C#

應用場景

主控台應用程式在伺服器長時間運行,可能因使用者關閉視窗、登出、系統關機等原因被終止。透過 Win32 API SetConsoleCtrlHandler 註冊回呼,可在進程結束前執行清理(寫入日誌、釋放資源、優雅關閉連線)。

完整程式碼

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Diagnostics;

namespace ConsoleCtrlDemo
{
    class Program
    {
        // 1. 定義回呼委派與常數
        private delegate bool CtrlHandler(int ctrlType);
        private const int CTRL_C_EVENT = 0;
        private const int CTRL_BREAK_EVENT = 1;
        private const int CTRL_CLOSE_EVENT = 2;       // 使用者點擊視窗關閉鈕
        private const int CTRL_LOGOFF_EVENT = 5;      // 使用者登出
        private const int CTRL_SHUTDOWN_EVENT = 6;    // 系統關機

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool SetConsoleCtrlHandler(CtrlHandler handler, bool add);

        static void Main(string[] args)
        {
            CtrlHandler handler = ConsoleCtrlHandler;
            bool ok = SetConsoleCtrlHandler(handler, true);
            Console.WriteLine(ok ? "Handler 註冊成功" : "Handler 註冊失敗");

            Console.WriteLine("程式執行中... 按 Ctrl+C 或關閉視窗測試");
            Console.ReadLine(); // 保持主執行緒存活
        }

        private static bool ConsoleCtrlHandler(int ctrlType)
        {
            switch (ctrlType)
            {
                case CTRL_CLOSE_EVENT:
                case CTRL_LOGOFF_EVENT:
                case CTRL_SHUTDOWN_EVENT:
                    Console.WriteLine($"收到關閉訊號:{ctrlType},開始清理...");
                    // 模擬清理工作(最多 10 秒,系統會強制終止)
                    for (int i = 0; i < 10; i++)
                    {
                        Console.WriteLine($"清理步驟 {i + 1}/10");
                        Thread.Sleep(1000);
                    }
                    Console.WriteLine("清理完成,程式即將結束");
                    return true; // 返回 true 表示已處理,系統不再傳遞給下一個 handler

                case CTRL_C_EVENT:
                case CTRL_BREAK_EVENT:
                    Console.WriteLine("收到 Ctrl+C / Ctrl+Break,忽略");
                    return true; // 攔截,不讓預設處理器終止程式

                default:
                    return false;
            }
        }
    }
}

關鍵細節

事件觸發時機處理時限
CTRL_CLOSE_EVENT使用者點擊視窗 [×]約 10 秒(Windows 10 可透過註冊表調整)
CTRL_LOGOFF_EVENT使用者登出同左
CTRL_SHUTDOWN_EVENT系統關機/重啟同左
  • 回呼執行緒:Windows 會建立新執行緒呼叫 handler,不可在裡面做 UI 操作或阻塞過久。
  • 返回值:true = 已處理,阻止預設行為;false = 交給下一個 handler 或預設處理器。
  • 部署建議:生產環境建議改用 Windows Service 或 .NET Generic Host (IHostedService),原生支援啟動/停止生命週期,無需 P/Invoke。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved