背景: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 }
調用:線程
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