『片斷』ShellHelper 控制檯程序 的 程序調用(支持輸入命令獲得返回字符串輸出)

背景:shell

> 以前作 OGG 時,被 OGG的配置 噁心到了。(OGG是啥,這裏就不解釋了)異步

> 總之就是一個 控制檯程序,老是得手動執行一堆命令,每次都得輸入 —— 實在是打字打累了。ide

> 因而,搜索:Shell控制輸入輸出 的代碼 —— 沒有找到完美的。【部分網友給出的每每是:一堆命令,獲得所有輸出 —— 而我要的是:輸入一行命令就獲得對應的輸出】this

 

源碼:spa

 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 = "\r\n" + string.Join("\r\n", 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 = "\r\n" + string.Join("\r\n", 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");

 

截圖:code

相關文章
相關標籤/搜索