• 『片段』ShellHelper 控制台程序 的 程序调用(支持输入命令得到返回字符串输出)


    背景:

    > 之前做 OGG 时,被 OGG的配置 恶心到了。(OGG是啥,这里就不解释了)

    > 总之就是一个 控制台程序,总是得手动执行一堆命令,每次都得输入 —— 实在是打字打累了。

    > 于是,搜索:Shell控制输入输出 的代码 —— 没有找到完美的。【部分网友给出的往往是:一堆命令,得到全部输出 —— 而我要的是:输入一行命令就得到对应的输出】

    源码:

      1 using System;
      2 using System.Collections.Generic;
      3 using System.Diagnostics;
      4 using System.Threading;
      5 
      6 namespace Temp
      7 {
      8     /// <summary>
      9     /// 控制台程序Shell辅助类
     10     /// </summary>
     11     public class ShellHelper
     12     {
     13         private static List<ShellInfo> m_ListShell = null;
     14         private static Thread m_ManageShell = null;
     15         private static readonly object m_Locker = new object();
     16 
     17         public static bool IsManageShellThread
     18         {
     19             get { return Thread.CurrentThread == m_ManageShell; }
     20         }
     21 
     22 
     23         public static ShellInfo Start(string exePath, ShellInfoReadLine ReadLine)
     24         {
     25             ShellInfo shellInfo = new ShellInfo();
     26             Process process = shellInfo.Process = new Process();
     27             process.StartInfo.FileName = exePath;
     28             process.StartInfo.UseShellExecute = false;
     29             process.StartInfo.RedirectStandardInput = true;
     30             process.StartInfo.RedirectStandardOutput = true;
     31             process.StartInfo.RedirectStandardError = true;
     32             process.StartInfo.CreateNoWindow = true;
     33             //process.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;  
     34 
     35             process.OutputDataReceived += new DataReceivedEventHandler(Process_OutputDataReceived);
     36             process.ErrorDataReceived += new DataReceivedEventHandler(Process_ErrorDataReceived);
     37 
     38             process.EnableRaisingEvents = true;                      // 启用Exited事件  
     39             process.Exited += new EventHandler(Process_Exited);   // 注册进程结束事件  
     40 
     41             process.Start();
     42             process.BeginOutputReadLine();
     43             process.BeginErrorReadLine();
     44             process.StandardInput.WriteLine();
     45 
     46             shellInfo.ReadLine = ReadLine;
     47 
     48             if (m_ListShell == null) m_ListShell = new List<ShellInfo>();
     49             m_ListShell.Add(shellInfo);
     50             InitShellManageThread();
     51             return shellInfo;
     52         }
     53 
     54         private static void InitShellManageThread()
     55         {
     56             if (m_ManageShell == null)
     57             {
     58                 m_ManageShell = new Thread(ManageShell_ThreadWork);
     59                 m_ManageShell.IsBackground = true;
     60                 m_ManageShell.Start();
     61             }
     62         }
     63         private static void ManageShell_ThreadWork()
     64         {
     65             while (m_ListShell != null && m_ListShell.Count >= 1)
     66             {
     67                 try
     68                 {
     69                     lock (m_Locker)
     70                     {
     71                         foreach (ShellInfo shell in m_ListShell)
     72                             if (shell != null) shell.InvokeInputOutput();
     73                     }
     74 
     75                     //线程休眠 50毫秒
     76                     AutoResetEvent eventHandle = new AutoResetEvent(false);
     77                     eventHandle.WaitOne(50);
     78                     eventHandle.Dispose();
     79                 }
     80                 catch (Exception ex) { Console.WriteLine("ERR: " + ex.ToString()); }
     81             }
     82         }
     83 
     84         private static void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
     85         {
     86             try
     87             {
     88                 ShellInfo shell = FindShellInfo(sender as Process);
     89                 if (shell != null) shell.DataReceived(e.Data);
     90             }
     91             catch (Exception ex) { Console.WriteLine("ERR: " + ex.ToString()); }
     92         }
     93         private static void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
     94         {
     95             try
     96             {
     97                 ShellInfo shell = FindShellInfo(sender as Process);
     98                 if (shell != null) shell.ErrorReceived(e.Data);
     99             }
    100             catch (Exception ex) { Console.WriteLine("ERR: " + ex.ToString()); }
    101         }
    102         private static void Process_Exited(object sender, EventArgs e)
    103         {
    104         }
    105 
    106         public static ShellInfo FindShellInfo(Process process)
    107         {
    108             if (process == null) return null;
    109             ShellInfo shell = m_ListShell.Find(x => x.Process == process);
    110             return shell;
    111         }
    112     }
    113 
    114     public class ShellInfo
    115     {
    116         private ShellState m_State = ShellState.Wait;
    117         private DateTime m_StateTime = DateTime.MinValue;
    118 
    119         private string m_LastOutLine;
    120         private List<ShellLine> m_ListWrite = new List<ShellLine>();
    121         private List<string> m_ListData = new List<string>();
    122         private List<string> m_ListError = new List<string>();
    123 
    124 
    125 
    126 
    127         public Process Process { get; set; }
    128         public ShellInfoReadLine ReadLine { get; set; }
    129 
    130         public ShellState State
    131         {
    132             get { return m_State; }
    133             private set
    134             {
    135                 m_State = value;
    136                 m_StateTime = DateTime.Now;
    137                 m_EventHandle.Set();
    138             }
    139         }
    140 
    141 
    142         public string PrevCmd { get { return string.Empty; } }
    143         public string NextCmd { get { return string.Empty; } }
    144 
    145         public void Close()
    146         {
    147             try { if (Process != null && !Process.HasExited) Process.Close(); }
    148             catch { }
    149         }
    150 
    151 
    152 
    153 
    154         #region  输 入 输 出 处 理
    155 
    156         private DateTime m_DataTime = DateTime.MinValue;
    157         private DateTime m_ErrorTime = DateTime.MinValue;
    158         private AutoResetEvent m_EventHandle = new AutoResetEvent(false);
    159         private ManualResetEvent m_EventWaitLogoOutputHandle = new ManualResetEvent(false);
    160         private AutoResetEvent m_EventAwaitWriteHandle = new AutoResetEvent(false);
    161         private const int MAX_UIWAIT_MILLSECOND = 60 * 1000;
    162 
    163         /// <summary>
    164         /// 等待 Shell 的 Logo输出结束 (也就是 刚启动Shell程序时, Shell程序最先输出文本, 然后才允许用户输入, 这里等待的就是 最先输出文本的过程)
    165         /// </summary>
    166         public void WaitLogoOuput()
    167         {
    168             if (ShellHelper.IsManageShellThread) return;
    169             m_EventWaitLogoOutputHandle.WaitOne(MAX_UIWAIT_MILLSECOND);
    170         }
    171         /// <summary>
    172         /// 阻塞当前线程, 直到当前 Shell 处于 指定的状态
    173         /// </summary>
    174         public void WaitState(ShellState state)
    175         {
    176             if (ShellHelper.IsManageShellThread || m_State == ShellState.Exited) return;
    177 
    178             const int JOIN_MILL_SECOND = 100; //等待毫秒数
    179             while (m_State != ShellState.Exited && (m_State & state) != m_State)
    180                 m_EventHandle.WaitOne(JOIN_MILL_SECOND);
    181         }
    182 
    183         /// <summary>
    184         /// 向Shell中, 输入一段命令, 且等待命令返回 执行后的输出字符串.
    185         /// </summary>
    186         public string WriteLine(string cmd)
    187         {
    188             return WriteLine(cmd, MAX_UIWAIT_MILLSECOND);
    189         }
    190         /// <summary>
    191         /// 向Shell中, 输入一段命令, 且等待命令返回 执行后的输出字符串.
    192         /// </summary>
    193         public string WriteLine(string cmd, int ms)
    194         {
    195             if (ms < 0) ms = MAX_UIWAIT_MILLSECOND;
    196             WaitLogoOuput();
    197             WaitState(ShellState.Input | ShellState.Wait);
    198             State = ShellState.Input;
    199 
    200             if (m_ListWrite == null) m_ListWrite = new List<ShellLine>();
    201 
    202             cmd = (cmd ?? string.Empty).Trim();
    203             ShellLine cmdLine = this.CurrLine = new ShellLine(m_LastOutLine, cmd);
    204             m_ListWrite.Add(cmdLine);
    205 
    206             m_EventAwaitWriteHandle.Reset();
    207             m_EventAwaitWriteHandle.WaitOne(ms);
    208             return cmdLine.Result;
    209         }
    210         /// <summary>
    211         /// 向Shell中, 以异步模式输入一段命令, 命令返回的输出字符串, 可以通过 ReadLine 回调捕获
    212         /// </summary>
    213         public void BeginWriteLine(string cmd)
    214         {
    215             WaitLogoOuput();
    216             WaitState(ShellState.Input | ShellState.Wait);
    217             State = ShellState.Input;
    218 
    219             if (m_ListWrite == null) m_ListWrite = new List<ShellLine>();
    220             cmd = (cmd ?? string.Empty).Trim();
    221             ShellLine cmdLine = this.CurrLine = new ShellLine(m_LastOutLine, cmd);
    222             m_ListWrite.Add(cmdLine);
    223             //m_EventAwaitWriteHandle.Reset();
    224             //m_EventAwaitWriteHandle.WaitOne(MAX_UIWAIT_MILLSECOND);
    225         }
    226 
    227         protected ShellLine CurrLine { get; set; }
    228 
    229         public void DataReceived(string str)
    230         {
    231             WaitState(ShellState.Output | ShellState.Wait);
    232             State = ShellState.Output;
    233 
    234 
    235             ShellLine cmdLine = this.CurrLine;
    236             if (cmdLine != null && !cmdLine.IsEmpty && !string.IsNullOrEmpty(str) && !cmdLine.Output)
    237             {
    238                 Process.StandardInput.WriteLine();
    239                 string diffStr = cmdLine.GetDiffString(str);
    240                 if (!string.IsNullOrEmpty(diffStr)) m_ListData.Add(diffStr);
    241                 cmdLine.Output = true;
    242                 return;
    243             }
    244 
    245             if (cmdLine != null) cmdLine.Output = true;
    246             m_ListData.Add(str);
    247             State = ShellState.Output;
    248         }
    249         public void ErrorReceived(string err)
    250         {
    251             WaitState(ShellState.OutputError | ShellState.Wait);
    252             State = ShellState.OutputError;
    253 
    254             m_ListError.Add(err);
    255             State = ShellState.OutputError;
    256         }
    257 
    258 
    259 
    260         public void InvokeInputOutput()
    261         {
    262             if (Process == null || Process.HasExited)
    263             {
    264                 m_EventHandle.Set();
    265                 m_EventWaitLogoOutputHandle.Set();
    266                 m_EventAwaitWriteHandle.Set();
    267                 return;
    268             }
    269 
    270             //100 ms 没有进行 输入、输出 操作, 则管理线程开始接收 Shell的处理
    271             const int DIFF_MILL_SECOND = 100;
    272             if (/*m_State != ShellState.Wait && */(DateTime.Now - m_StateTime).TotalMilliseconds > DIFF_MILL_SECOND)
    273             {
    274 
    275                 ShellInfoReadLine handle = this.ReadLine;
    276                 ShellLine waitCmdLine = this.CurrLine;
    277                 string waitCmd = waitCmdLine == null ? string.Empty : waitCmdLine.Cmd;
    278 
    279                 if (waitCmdLine != null || (m_ListWrite == null || m_ListWrite.Count <= 0))
    280                 {
    281                     #region  正常输出
    282                     if (m_ListData != null && m_ListData.Count >= 1)
    283                     {
    284                         string last = m_ListData[m_ListData.Count - 1];
    285                         if (!string.IsNullOrEmpty(last) && !last.Trim().EndsWith(">")) m_ListData.Add(string.Empty);
    286 
    287                         string data = "
    " + string.Join("
    ", m_ListData);
    288                         m_LastOutLine = last;
    289                         m_ListData.Clear();
    290                         handle(waitCmd, data);
    291                         if (waitCmdLine != null) waitCmdLine.Result = data;
    292                         this.CurrLine = null;
    293                         m_EventAwaitWriteHandle.Set();
    294                         m_EventWaitLogoOutputHandle.Set();
    295                     }
    296                     #endregion
    297 
    298                     #region  异常输出
    299                     if (m_ListError != null && m_ListError.Count >= 1)
    300                     {
    301                         string last = m_ListError[m_ListError.Count - 1];
    302                         if (!string.IsNullOrEmpty(last) && !last.Trim().EndsWith(">")) m_ListError.Add(string.Empty);
    303 
    304                         string error = "
    " + string.Join("
    ", m_ListError);
    305                         m_ListError.Clear();
    306                         handle(waitCmd, error);
    307                         if (waitCmdLine != null) waitCmdLine.Result = error;
    308                         this.CurrLine = null;
    309                         m_EventAwaitWriteHandle.Set();
    310                         m_EventWaitLogoOutputHandle.Set();
    311                     }
    312                     #endregion
    313                 }
    314 
    315                 #region  执行输入
    316                 if (m_ListWrite != null && m_ListWrite.Count >= 1)
    317                 {
    318                     ShellLine cmdLine = m_ListWrite[0];
    319                     this.Process.StandardInput.WriteLine(cmdLine.Cmd);
    320                     m_ListWrite.RemoveAt(0);
    321                     //输入命令后, 优先接收 Shell 的 错误信息
    322                     State = ShellState.OutputError;
    323                 }
    324                 else
    325                     State = ShellState.Wait;
    326                 #endregion
    327 
    328 
    329             }
    330         }
    331 
    332         #endregion
    333 
    334 
    335     }
    336     public class ShellLine
    337     {
    338         public ShellLine(string cmd)
    339         {
    340             this.Cmd = cmd;
    341         }
    342         public ShellLine(string tip, string cmd)
    343         {
    344             this.Tip = tip;
    345             this.Cmd = cmd;
    346         }
    347 
    348         public string Tip { get; set; }
    349         public string Cmd { get; set; }
    350         public string Result { get; set; }
    351 
    352 
    353         public bool Output { get; set; }
    354         public bool IsEmpty
    355         {
    356             get { return string.IsNullOrEmpty(this.Cmd); }
    357         }
    358         public string Line
    359         {
    360             get { return Tip + Cmd; }
    361         }
    362 
    363 
    364         public string GetDiffString(string str)
    365         {
    366             if (string.IsNullOrEmpty(str)) return string.Empty;
    367 
    368             string tip = this.Tip;
    369             string line = this.Line;
    370             if (str.StartsWith(line)) return str.Substring(line.Length);
    371             if (str.StartsWith(tip)) return str.Substring(tip.Length);
    372             return str;
    373         }
    374     }
    375 
    376     [Flags]
    377     public enum ShellState
    378     {
    379         /// <summary>
    380         /// Shell 暂时没有任何输入输出, 可能是在等待用户输入, 也可能是Shell正在处理数据
    381         /// </summary>
    382         Wait = 1,
    383         /// <summary>
    384         /// 正在向 Shell 中写入命令
    385         /// </summary>
    386         Input = 2,
    387         /// <summary>
    388         /// Shell 正式输出 正常信息
    389         /// </summary>
    390         Output = 4,
    391         /// <summary>
    392         /// Shell 正在输出 错误信息
    393         /// </summary>
    394         OutputError = 8,
    395         /// <summary>
    396         /// Shell 已经退出
    397         /// </summary>
    398         Exited = 16,
    399 
    400 
    401     }
    402 
    403     public delegate void ShellInfoReadLine(string cmd, string result);
    404 
    405 }
    View Code

    调用:

    1             ShellInfo shell = ShellHelper.Start("cmd.exe", (cmd, rst) => {  });
    2             shell.WaitLogoOuput(); //先等程序把 LOGO 输出完
    3 
    4             string aaa = shell.WriteLine("D:");  //相当于在 cmd 中输入 D:
    5             string bbb = shell.WriteLine("dir"); //相当于在 cmd 中输入 dir
    string ccc = shell.WriteLine("AAAA");

    截图:

  • 相关阅读:
    iOS数字媒体开发浅析
    Servlet
    Qt之图形(绘制文本)
    Qt之图形(转换)
    asp.net 缓存公共类
    logback.xml
    ext树菜单实体类
    ext,exrReturn新增,修改删除等用
    ExtPager ,分页
    ExtGridReturn ,存放ext的实体类集合和总数
  • 原文地址:https://www.cnblogs.com/shuxiaolong/p/ShellHelper.html
Copyright © 2020-2023  润新知