Windows 平台一个正确控制台捕获(Control + C、关闭控制台、Control + Backspace 等的新姿态(基于 SetConsoleCtrlHandler API函数)

53 篇文章 2 订阅

Samples:

namespace Ppc
{
    using System;
    using System.Threading;
    using Ppp.Core;
    using Ppp.IO;
    using Ppp.Vpn;
    using Ppp.Vpn.Ppp;
    using SimpleJSON;

    public static class Program
    {
        private readonly static AutoResetEvent exitEventWaitable = new AutoResetEvent(false);
        private static Ppp pppWaitable = null;

        private static bool Exit()
        {
            exitEventWaitable.Set();
            if (pppWaitable != null)
            {
                pppWaitable.Dispose();
            }
            return true;
        }

        private static bool WaitForExit()
        {
            try
            {
                exitEventWaitable.WaitOne();
            }
            catch (Exception) { }
            return Exit();
        }

        [STAThread]
        private static void Main(string[] args)
        {
            Environments.SetConsoleCtrlHandler(Environments.
                Pinned<Environments.HandlerRoutine>((ctrlTypes) =>
                {
                    switch (ctrlTypes)
                    {
                        case Environments.CtrlTypes.CTRL_BREAK_EVENT:
                            return false;
                        default:
                            return Exit();
                    };
                }));
            ApplicationConfiguration configuration = new ApplicationConfiguration();
            if (FileAuxiliary.TryReadAllText("appsettings.json", out string json))
            {
                configuration.Load(JSON.Parse(json));
            }
            SocketExtension.PeriodGCCollect = configuration.PeriodGCCollect;
            using (pppWaitable = new Ppp(configuration))
            {
                pppWaitable.Listen();
                WaitForExit();
            }
        }
    }
}

Environments.cs

namespace Ppp.Core
{
    using System;
    using System.Diagnostics;
    using System.IO;
    using System.Net;
    using System.Linq;
    using System.Runtime.InteropServices;

    public static class Environments
    {
        public static string GetCommandArgumentString(this string[] args, string key)
        {
            if (args == null || args.Length <= 0)
                return null;
            for (int i = 0; i < args.Length; i++)
            {
                string s = (args[i] ?? string.Empty).TrimStart().TrimEnd();
                int j = s.IndexOf('=');
                if (j < 0)
                {
                    if (key != s)
                        continue;
                    return s;
                }
                string p = s.Substring(0, j);
                if (string.IsNullOrEmpty(p))
                    continue;
                if (p != key)
                    continue;
                return s.Substring(j + 1).TrimStart().TrimEnd();
            }
            return null;
        }

        public enum CtrlTypes
        {
            CTRL_C_EVENT = 0,
            CTRL_BREAK_EVENT,
            CTRL_CLOSE_EVENT,
            CTRL_LOGOFF_EVENT = 5,
            CTRL_SHUTDOWN_EVENT
        }

        [UnmanagedFunctionPointer(CallingConvention.StdCall)]
        public delegate bool HandlerRoutine(CtrlTypes CtrlType);

        [DllImport("kernel32.dll", SetLastError = true)]
        private static extern bool SetConsoleCtrlHandler(
            [MarshalAs(UnmanagedType.FunctionPtr)]HandlerRoutine Handler, [MarshalAs(UnmanagedType.Bool)]bool Add);

        public static T Pinned<T>(T obj)
        {
            GCHandle.Alloc(obj);
            return (T)obj;
        }

        public static void SetConsoleCtrlHandler(HandlerRoutine routine)
        {
            if (routine == null)
            {
                throw new ArgumentNullException(nameof(routine));
            }
            SetConsoleCtrlHandler(routine, true);
        }

        public static string[] GetCommandLineArgs()
        {
            string[] s = Environment.GetCommandLineArgs();
            if (s == null || s.Length <= 0)
            {
                return new string[0];
            }
            return s.Skip(1).ToArray();
        }

        public static long? GetCommandArgumentInt64(this string[] args, string key)
        {
            string s = args.GetCommandArgumentString(key);
            if (string.IsNullOrEmpty(s))
                return null;
            if (!long.TryParse(s, out long r))
                return null;
            return r;
        }

        public static ulong? GetCommandArgumentUInt64(this string[] args, string key)
        {
            string s = args.GetCommandArgumentString(key);
            if (string.IsNullOrEmpty(s))
                return null;
            if (!ulong.TryParse(s, out ulong r))
                return null;
            return r;
        }

        public static IPEndPoint GetServerEndPoint(this string[] args)
        {
            string server = args.GetCommandArgumentString("--server");
            if (string.IsNullOrEmpty(server))
                server = "127.0.0.1";
            long port = args.GetCommandArgumentInt64("--port") ?? 1080;
            if (port <= IPEndPoint.MinPort || port > IPEndPoint.MaxPort)
                port = 1080;
            return new IPEndPoint(IPAddress.Parse(server), Convert.ToInt32(port));
        }

        public static bool PrintHelpText(this string[] args)
        {
            if (args != null && args.Length > 0)
            {
                string s = args.GetCommandArgumentString("--help");
                if (string.IsNullOrEmpty(s))
                    s = args.GetCommandArgumentString("--?");
                if (string.IsNullOrEmpty(s))
                    return false;
            }
            Console.WriteLine($"usage: {Path.GetFileNameWithoutExtension(AppDomain.CurrentDomain.FriendlyName)} --server=127.0.0.1 --port=1080");
            return true;
        }

        [DllImport("msvcrt.dll", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl, EntryPoint = "system")]
        public static extern void System([MarshalAs(UnmanagedType.LPStr)]string command);

        public static bool ExecuteCommands(params string[] commands)
        {
            return ExecuteCommands(true, commands);
        }

        public static bool ExecuteCommands(bool waitForExit, params string[] commands)
        {
            if (commands == null)
            {
                return false;
            }
            for (int i = 0; i < commands.Length; i++)
            {
                string arguments = commands[i];
                if (string.IsNullOrEmpty(arguments))
                {
                    continue;
                }
                string fileName = string.Empty;
                int j = arguments.IndexOf(' ');
                if (j < 0)
                {
                    fileName = arguments;
                }
                else
                {
                    fileName = arguments.Substring(0, j);
                    arguments = arguments.Substring(j + 1);
                }
                var si = new ProcessStartInfo()
                {
                    CreateNoWindow = true,
                    UseShellExecute = false,
                    FileName = fileName,
                    Arguments = arguments,
                };
                try
                {
                    using (var po = Process.Start(si))
                    {
                        try
                        {
                            if (waitForExit)
                            {
                                po.WaitForExit();
                            }
                            return true;
                        }
                        catch (Exception)
                        {
                            return false;
                        }
                    }
                }
                catch (Exception)
                {
                    return false;
                }
            }
            return false;
        }
    }
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值