『片段』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 = "\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");

 

截图:

 

posted on 2018-06-28 19:57  InkFx  阅读(536)  评论(0编辑  收藏  举报