Unity 调用外部exe的完美封装

手写不易,点赞支持,支持纯手工,转载请标明出处

using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;
using UnityEngine;

public class ExecuteEXE
{
    private ExecuteEXE() { }
    private static ExecuteEXE instance;
    public static ExecuteEXE Instance {
        get {
            if (instance==null)
            {
                instance = new ExecuteEXE();
            }
            return instance;
        }
    }
    
    public enum State
    {
        Success=0,//总状态
        Failure,
        Error,//出错了

        ThreadMessage =100,//线程信息
        ProcessMessage =200,//进程信息
    }
    public class Message
    {
        public State state;//状态码
        public string msg;//消息
        public StackTrace stack;//堆栈
    }

    private static readonly object locker = new object();
    private readonly string logFilter = "- INFO:";
    private readonly int timeoutMs = 60 * 1000;//进程超时时间,毫秒
    private Queue<Message> message;
    private Thread thread;
    private Process process;
    /// <summary>
    /// 对外输出message,消息在update里轮询,后期维护的成本要比用委托低
    /// </summary>
    public Message GetMessage()
    {
        lock (locker)
        {
            if (message == null || message.Count <= 0)
            {
                return null;
            }
            return message.Dequeue();
        }
    }

    /// <summary>
    /// 异步执行exe
    /// </summary>
    public void AsyncExecute(string exePath, params string[] args)
    {
        ForceDispose();
        thread = new Thread(() =>
        {
            try
            {
                process = new Process();
                process.StartInfo.CreateNoWindow = true;
                process.StartInfo.ErrorDialog = false;
                process.StartInfo.UseShellExecute = false;
                process.StartInfo.RedirectStandardOutput = true;
                process.StartInfo.RedirectStandardError = true;
                process.StartInfo.RedirectStandardInput = false;
                process.StartInfo.StandardOutputEncoding = Encoding.UTF8;
                process.StartInfo.StandardErrorEncoding = Encoding.UTF8;
                process.StartInfo.FileName = exePath;
                if (args != null && args.Length > 0)
                {
                    foreach (var arg in args)
                    {
                        process.StartInfo.Arguments += " " + arg;
                    }
                }
                process.OutputDataReceived += new DataReceivedEventHandler((s, e) =>
                {
                    //过滤掉INFO级别的日志
                    if (e != null && e.Data != null && !e.Data.Contains(logFilter))
                    {
                        AddMessage(State.ProcessMessage, e.Data);
                    }
                });
                process.ErrorDataReceived += new DataReceivedEventHandler((s, e) =>
                {
                    if (e != null && e.Data != null)
                    {
                        AddMessage(State.Error, e.Data);
                    }
                });
                process.Start();
                process.BeginOutputReadLine();
                process.BeginErrorReadLine();
                bool isFinish=process.WaitForExit(timeoutMs);
                int timeoutCode = -999999;//isFinish=false时,表示进程超时
                int exitCode = isFinish ? process.ExitCode : timeoutCode;
                System.DateTime startTime = isFinish ? process.StartTime : System.DateTime.Now;
                System.DateTime exitTime = isFinish ? process.ExitTime : System.DateTime.Now;//isFinish=false时,调用ExitCode,ExitTime会抛出异常:Process must exit before requested information can be determined.
                process.Close();
                process.Dispose();
                process = null;
                if (exitCode == timeoutCode)
                {
                    AddMessage(State.Error, "进程超时");
                }
                else if (exitCode == 0)
                {
                    AddMessage(State.Success, "完成,进程ExitCode:" + exitCode + ",StartTime:" + startTime.ToString("yyyy-MM-dd HH:mm:ss.fff") + ",ExitTime:" + exitTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                }
                else
                {
                    AddMessage(State.Failure, "失败,进程ExitCode:" + exitCode + ",StartTime:" + startTime.ToString("yyyy-MM-dd HH:mm:ss.fff") + ",ExitTime:" + exitTime.ToString("yyyy-MM-dd HH:mm:ss.fff"));
                }
            }
            catch (System.Exception e)
            {
                AddMessage(State.Error, "进程异常:" + e.Message);
            }
        });
        thread.Start();
    }
    /// <summary>
    /// 强制释放所有内容
    /// </summary>
    /// <returns></returns>
    public bool ForceDispose()
    {
        bool processError = ForceDisposeProcess();
        bool threadError = ForceDisposeThread();
        ForceDisposeMessage();
        return processError || threadError;
    }

    /// <summary>
    /// 添加消息
    /// </summary>
    void AddMessage(State state, string msg)
    {
        lock (locker)
        {
            if (message == null)
            {
                message = new Queue<Message>();
            }
            Message m = new Message()
            {
                state = state,
                msg = msg,
                stack = new StackTrace(true)
            };
            message.Enqueue(m);
        }
    }
    /// <summary>
    /// 强制释放线程
    /// </summary>
    bool ForceDisposeThread()
    {
        bool isError = false;
        if (thread == null || !thread.IsAlive)
        {
            return isError;
        }
        try
        {
            thread.Abort();
        }
        catch (System.Exception e)
        {
            AddMessage(State.ThreadMessage, "Thread Abort Error:" + e.Message);
            isError = true;
        }
        return isError;
    }
    /// <summary>
    /// 强制释放进程
    /// </summary>
    bool ForceDisposeProcess()
    {
        bool isError = false;
        if (process == null)
        {
            return isError;
        }
        try
        {
            process.Close();
            process.Dispose();
        }
        catch (System.Exception e)
        {
            AddMessage(State.ProcessMessage, "Process Dispose Error:" + e.Message);
            isError = true;
        }
        return isError;
    }
    /// <summary>
    /// 释放消息队列
    /// </summary>
    private void ForceDisposeMessage()
    {
        lock (locker)
        {
            if (message != null)
            {
                message.Clear();
            }
            message = null;
        }
    }
}

  

posted on 2021-12-16 11:26  Jason_c  阅读(724)  评论(0编辑  收藏  举报